I have a code taken from github. It should generate random faces from images, works fine. I now wanted to add a new gender to the code. At the moment it has "Male" and "Female" I wanted to add "Zombie" and "Alien". Now I added the gender like the Male and Female are added in the code, this also works. The point where I can't find a solution is, that I added an else if condition to make the alien and zombie more rare than male and female, but this isn't working. The code only assigns a random gender face and there is no difference how often a gender appears.
I added the code below, I'm sorry that it's not reproducable. you can get the working code here: Master file, Github
const fs = require("fs");
const mergeImg = require('merge-img');
const outputFolder = "./generated_faces";
const outputCharacterJSON = "./generated_faces/characters.json";
const outputAttributesJS = "./generated_faces/attributes.json";
const desiredCount = 1000;
const totalFaces = 89820;
// const ext = ".png";
// const partFolder = "./test_face_parts";
// const partTypes = [
// { name: "head", count: 1, offset: {x: 0, y: 0}, attrNames: [""], required: true },
// { name: "nose", count: 2, offset: {x: -2400, y: 0}, attrNames: ["Normal nose", "Potato nose"], required: false },
// { name: "eyes", count: 2, offset: {x: -2400, y: 0}, attrNames: ["Normal eyes", "Crazy eyes"], required: true },
// { name: "hair", count: 2, offset: {x: -2400, y: 0}, attrNames: ["Blonde hair", "Dark hair"], required: true },
// { name: "mouth", count: 3, offset: {x: -2400, y: 0}, attrNames: ["Red mouth", "Black mouth", "Blue mouth"], required: true },
// ];
const ext = ".png";
const partFolder = "./face_parts";
const partTypes = [
{ name: "back/b", count: 8, offset: {x: 0, y: 0}, attrNames: ["", "", "", "", "", "", "", ""], attrSex: ["u", "u", "u", "u", "u", "u", "u", "u"], required: true },
{ name: "face/face", count: 7, offset: {x: -240, y: 0}, attrNames: ["brown", "dark brown", "albino", "gold", "grey", "Zombie", "Alien"], attrSex: ["u","u","u","u","u","z","a"], required: true },
{ name: "nose/n", count: 8, offset: {x: -240, y: 0}, attrNames: ["Nose Black", "Nose Pink", "Nose Brown", "Nose Red", "Nose Rosé", "Nose light red", "Nose light blue", "Nose sea green"], attrSex: ["u", "u", "u", "u", "u", "u", "u", "u"], required: true },
{ name: "eyes/eyes", count: 25, offset: {x: -240, y: 0}, attrNames: ["dot black", "blue normal", "blue sq", "blue rage", "green rage", "red rage", "red normal", "green normal", "türkis sq", "türkis blind r", "blue blind l","black bad","pink bad","türkis blue bad","türkis blue normal","blue türkis normal","pink rage","green rage","green bad","blue bad","white bad","red bad", "red sad","green sad","blue sad"], attrSex: ["u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u"], required: true },
{ name: "ears/ears", count: 24, offset: {x: -240, y: 0}, attrNames: ["Mint", "Green", "Red", "Orange", "Silver", "Light Blue", "Bronze", "Rosè", "Gold","Purple", "Mint Bush", "Green Bush", "Red Bush", "Orange Bush", "Silver Bush", "Light Blue Bush", "Bronze Bush", "Rosé Bush", "Gold Bush", "Purple Bush", "Dark Blue Bush", "Dark Blue", "Grey", "Grey Bush"], attrSex: ["u","u", "u", "u", "u", "u", "u", "u", "u", "u","u","u","u","u","u","u","u","u","u","u","u","u","u","u"], required: true },
{ name: "mouth/m", count: 12, offset: {x: -240, y: 0}, attrNames: ["Black deep", "Black high", "Mouth open", "light red deep", "open big teeth", "smiling", "big sad", "thongue out", "sea green", "light blue", "light brown", "dark blue"], attrSex: ["u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u", "u"], required: true },
{ name: "beard/beard", count: 4, offset: {x: -240, y: 0}, attrNames: ["Brown Beard", "", "Mustache-Beard", ""], attrSex: ["u", "u", "u", "u"], required: true },
];
function checkAttributeCompatibility(codeArr) {
let blondeHair = false;
let earring = false;
for (let i=0; i<partTypes.length; i++) {
if ((partTypes[i].name == "hair/hair") && (codeArr[i] == 10))
blondeHair = true;
if ((partTypes[i].name == "ears/ears") && (codeArr[i] >= 2))
earring = true;
}
if (earring && blondeHair) return false;
return true;
}
function mergeImagesToPng(images, output) {
return new Promise(function(resolve, reject) {
mergeImg(images)
.then((img) => {
// Save image as file
img.write(output, () => {
console.log(`Image ${output} saved`);
resolve();
});
});
// resolve();
});
}
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function detectGender(codeArr) {
let male = false;
let female = false;
let zombie = false;
let alien = false;
for (let i=0; i < partTypes.length; i++) {
if (codeArr[i] != 0) {
const attrGender = partTypes[i].attrSex[codeArr[i]-1];
if (attrGender == "m") male = true;
if (attrGender == "f") female = true;
if (attrGender == "z") zombie = true;
if (attrGender == "a") alien = true;
}
}
if (male && female) return "Invalid";
if (male && zombie) return "Invalid";
if (male && alien) return "Invalid";
if (female && alien) return "Invalid";
if (female && zombie) return "Invalid";
if (alien && zombie) return "Invalid";
if (male) return "Male";
if (female) return "Female";
if (zombie) return "Zombie";
if (alien) return "Alien";
var ranint = Math.floor(Math.random() * 1000) + 1;
if (ranint > 500 <998) return "Female";
else if (ranint < 2) return "Zombie";
else if (ranint > 998) return "Alien";
else return "Male";
}
async function saveFaceByCode(codeArr, outFile) {
let images = [];
for (let i=0; i < partTypes.length; i++) {
if (codeArr[i] != 0) {
const img = {
src: `${partFolder}/${partTypes[i].name}${codeArr[i]}${ext}`,
offsetX: partTypes[i].offset.x,
offsetY: partTypes[i].offset.y,
}
images.push(img);
}
}
// Generate image
await mergeImagesToPng(images, outFile);
}
async function generateFaces() {
// Array that lists all characters
let characters = [];
// Save attributes and generate map of attributes to saved array index
let attrArray = [];
let attrMap = {};
let attrFreq = {};
let attrCount = 0;
for (let i=0; i < partTypes.length; i++) {
for (let j=1; j<=partTypes[i].count; j++) {
if (partTypes[i].attrNames[j-1].length > 0) {
attrArray.push(partTypes[i].attrNames[j-1]);
attrMap[partTypes[i].attrNames[j-1]] = attrCount;
attrFreq[partTypes[i].attrNames[j-1]] = 0;
attrCount++;
}
}
}
let attrjs = `const attributes = ${JSON.stringify(attrArray)};`;
attrjs += "\n\nmodule.exports.attributes = attributes;";
fs.writeFileSync(outputAttributesJS, attrjs);
// "Code array" contains the code of current "face"
// Initialize it to the first "face"
let codeArr = [];
for (let i=0; i < partTypes.length; i++) {
if (partTypes[i].required)
codeArr.push(1);
else
codeArr.push(0);
}
let imgCount = 0;
// In the loop generate faces and increase the code by one
let exhausted = false;
while (!exhausted) {
// Check if combination is valid
let gender = detectGender(codeArr);
let valid = checkAttributeCompatibility(codeArr);
// Skip faces randomly to get close to desired count
const r = (getRandomInt(1000)+1)/1200;
// const r = 0;
if ((r <= desiredCount/totalFaces) && (gender != "Invalid") && (valid)) {
// Generate and save current face
await saveFaceByCode(codeArr, `${outputFolder}/image${imgCount}${ext}`);
// Add character with accessories
c = {
id: imgCount,
gender: gender,
attributes: []
};
for (let i=0; i < partTypes.length; i++) {
if (partTypes[i].attrNames.length != 0)
if (codeArr[i] != 0) {
let attrName = partTypes[i].attrNames[codeArr[i]-1];
if (attrName.length > 0) {
c.attributes.push(attrMap[attrName]);
attrFreq[attrName]++;
}
}
}
characters.push(c);
imgCount++;
} else {
// console.log(`Skipping. r = ${r}, gender = ${gender}, codeArr=${codeArr}`);
}
// Increate code by 1
let canIncrease = false;
for (let i=0; i < partTypes.length; i++) {
if (codeArr[i] < partTypes[i].count) {
canIncrease = true;
codeArr[i]++;
for (let j=i-1; j>=0; j--) {
if (partTypes[j].required)
codeArr[j] = 1;
else
codeArr[j] = 0;
}
break;
}
}
if (!canIncrease) exhausted = true;
if (imgCount == desiredCount) break;
}
// Save characters' JSON
fs.writeFileSync(outputCharacterJSON, JSON.stringify(characters));
console.log("Total generated characters: ", imgCount);
console.log("Attribute frequencies: ", attrFreq);
}
async function generateManually() {
// Женин любимый
code = [1, 5, 2, 3, 1, 1, 5, 1];
await saveFaceByCode(code, "test.png");
let punks = require("./generated_faces/characters.json");
c = {
id: 10000,
gender: "Male",
attributes: [3,7,13,21,29]
};
punks.push(c);
fs.writeFileSync("characters.json", JSON.stringify(punks));
}
async function main() {
await generateFaces();
// await generateManually();
}
main();
// function test() {
// code = [1, 6, 2, 4, 4, 1, 8, 1];
// console.log(detectGender(code));
// }
// test();
The part I edited is:
function detectGender(codeArr) {
let male = false;
let female = false;
let zombie = false;
let alien = false;
for (let i=0; i < partTypes.length; i++) {
if (codeArr[i] != 0) {
const attrGender = partTypes[i].attrSex[codeArr[i]-1];
if (attrGender == "m") male = true;
if (attrGender == "f") female = true;
if (attrGender == "z") zombie = true;
if (attrGender == "a") alien = true;
}
}
if (male && female) return "Invalid";
if (male && zombie) return "Invalid";
if (male && alien) return "Invalid";
if (female && alien) return "Invalid";
if (female && zombie) return "Invalid";
if (alien && zombie) return "Invalid";
if (male) return "Male";
if (female) return "Female";
if (zombie) return "Zombie";
if (alien) return "Alien";
var ranint = Math.floor(Math.random() * 1000) + 1;
if (ranint > 500 <998) return "Female";
else if (ranint < 2) return "Zombie";
else if (ranint > 998) return "Alien";
else return "Male";
}
I know that this is not coded well... I'm just a beginner trying to modify something found online.
Aucun commentaire:
Enregistrer un commentaire