bool StudentLocalization::stepFindChinContours(const IntensityImage &image, FeatureMap &features) const { const Feature & mouthCenter = features.getFeature(Feature::FEATURE_MOUTH_CENTER); const Feature & chin = features.getFeature(Feature::FEATURE_CHIN); Feature & chinContour = features.getFeature(Feature::FEATURE_CHIN_CONTOUR); // The mouth could interfere with the localization of the chin contours. // Therefore use an offset based on which mouthcorner is the furthest away. // This however could still prove troublesome, so add a slight margin; // represented by the 'magic' number. const double radius = chin.getY() - mouthCenter.getY(); const double smallestOffsetRadiusFactor = 0.75; const double biggestOffsetRadiusFactor = 2; // // 180° matches half a circle. // 0° points to the east in goniometrics, where increasing angles are counter-clockwise. // Since the chin is usually on the bottompart of the image, the points either need to be // found clockwise (-180), or start looking at an offset. // const int halfCircle = 180; const int angleStepSize = 10; // roughly 19 points need to be found. // 0 through 18 does just that. for (int i = 0; i <= halfCircle / angleStepSize; ++i) { // Determine the angle of the line among which we try to look for a point on the chin's contour. int angle = halfCircle + i * angleStepSize; // The size of a step in both the horizontal and verticical direction along the line with the current angle. double xDir = std::cos(angle * M_PI / 180.0); double yDir = -std::sin(angle * M_PI / 180.0); // Normalized size of a step that is made alongside the current angle. const double increment = 1; // Make multiple steps alongside the current angle within bounds where it is likely a contour for the chin. for (double distance = radius * smallestOffsetRadiusFactor; distance < radius * biggestOffsetRadiusFactor; distance += increment) { // Determine the location to check for a contour of the chin. double xCheck = mouthCenter.getX() + (xDir * distance); double yCheck = mouthCenter.getY() + (yDir * distance); // Image should be thresholded grayscale, where the pixels are eiher 0 or 255; check in the middle of it. const unsigned char treshhold = 128; if (image.getPixel(xCheck, yCheck) <= treshhold) { chinContour.addPoint(Point2D<double>(xCheck, yCheck)); std::cout << "Found contour at: " << xCheck << "; " << yCheck << "\n"; break; } } } return (chinContour.getPoints().size() > 0); }
void Test::RunLocalizationTest(RGBImage* image) { DLLExecution * executor = new DLLExecution(image); executor->executePreProcessingStep1(false); executor->executePreProcessingStep2(false); executor->executePreProcessingStep3(false); executor->executePreProcessingStep4(false); executor->prepareLocalization(); IntensityImage* img = executor->resultPreProcessingStep4; HistogramLocalization localizer = HistogramLocalization(); FeatureMap features = FeatureMap(); FeatureMap detectedItems = localizer.locateHead(img, features); RGB colorRed(244, 67, 54); RGBImage * debug = ImageFactory::newRGBImage(executor->resultPreProcessingStep1->getWidth(), executor->resultPreProcessingStep1->getHeight()); ImageIO::intensityToRGB(*executor->resultPreProcessingStep1, *debug); for (int i = 0; i < 3; ++i) HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, Point2D<double>(detectedItems.getFeature(i).getX(), detectedItems.getFeature(i).getY()), colorRed); ImageIO::saveRGBImage(*debug, ImageIO::getDebugFileName("localisation.png")); ImageIO::showImage(*debug); }
bool StudentLocalization::stepFindChinContours(const IntensityImage &image, FeatureMap &features) const { //Get the position of the mouth Feature Mouth = features.getFeature(Feature::FEATURE_MOUTH_TOP); Point2D<double> MouthPosition; //Initialise the chin feature std::vector<Point2D<double>> ChinPositions; Feature Chin = Feature(Feature::FEATURE_CHIN); Feature ChinContour = Feature(Feature::FEATURE_CHIN_CONTOUR); int y = 0; int m = 0; //Draw a half circle starting from the center of the mouth for (int j = HALF_CIRCLE; j > 0; j -= DEGREE_STEP){ //reset the position of the mouth MouthPosition.set(Mouth.getX(), Mouth.getY()); MouthPosition.set(drawLine(j, START_POSITION, MouthPosition)); m = m + 1; for (int i = 0; i < MEASURE_RANGE; i++){ MouthPosition.set(drawLine(j, MEASURE_STEP, MouthPosition)); Intensity pixel = image.getPixel(MouthPosition.getX(), MouthPosition.getY()); // If the intensity of the current pixel is lower than 2 (which means it is black) if (pixel < 2){ // If the current angle is within the bounds of the half circle if (j < RIGHT_HALF && j > LEFT_HALF){ ChinContour.addPoint(drawLine(j, 2, MouthPosition)); } else{ //Draw a point on the mouth position, to indicate the detection failed. ChinContour.addPoint(MouthPosition); } break; } } } features.putFeature(ChinContour); return true; }
void drawFeatureDebugImage(IntensityImage &image, FeatureMap &features) { RGB colorRed(244, 67, 54); RGBImage * debug = ImageFactory::newRGBImage(image.getWidth(), image.getHeight()); ImageIO::intensityToRGB(image, *debug); //Nose Point2D<double> noseLeft = features.getFeature(Feature::FEATURE_NOSE_END_LEFT)[0]; Point2D<double> noseRight = features.getFeature(Feature::FEATURE_NOSE_END_RIGHT)[0]; Point2D<double> nostrilLeft = features.getFeature(Feature::FEATURE_NOSTRIL_LEFT)[0]; Point2D<double> nostrilRight = features.getFeature(Feature::FEATURE_NOSTRIL_RIGHT)[0]; Point2D<double> noseBottom = features.getFeature(Feature::FEATURE_NOSE_BOTTOM)[0]; //These (weird) methods can be used to draw debug points HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, noseLeft, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, noseRight, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, nostrilLeft, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, nostrilRight, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, noseBottom, colorRed); //Chin std::vector<Point2D<double>> points = features.getFeature(Feature::FEATURE_CHIN_CONTOUR).getPoints(); for (size_t i = 0; i < points.size(); i++) { HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, points[i], colorRed); } //Eye Feature leftEye = features.getFeature(Feature::FEATURE_EYE_LEFT_RECT); Feature rightEye = features.getFeature(Feature::FEATURE_EYE_RIGHT_RECT); //These (weird) methods can be used to draw debug rects HereBeDragons::AsHisTriumphantPrizeProudOfThisPride(*debug, leftEye[0], leftEye[1], colorRed); HereBeDragons::AsHisTriumphantPrizeProudOfThisPride(*debug, rightEye[0], rightEye[1], colorRed); //Head Feature headTop = features.getFeature(Feature::FEATURE_HEAD_TOP); Feature headLeftNoseMiddle = features.getFeature(Feature::FEATURE_HEAD_LEFT_NOSE_MIDDLE); Feature headLeftNoseBottom = features.getFeature(Feature::FEATURE_HEAD_LEFT_NOSE_BOTTOM); Feature headRightNoseMiddle = features.getFeature(Feature::FEATURE_HEAD_RIGHT_NOSE_MIDDLE); Feature headRightNoseBottom = features.getFeature(Feature::FEATURE_HEAD_RIGHT_NOSE_BOTTOM); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, headTop[0], colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, headLeftNoseMiddle[0], colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, headLeftNoseBottom[0], colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, headRightNoseMiddle[0], colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, headRightNoseBottom[0], colorRed); //Mouth Point2D<double> mouthTop = features.getFeature(Feature::FEATURE_MOUTH_TOP)[0]; Point2D<double> mouthBottom = features.getFeature(Feature::FEATURE_MOUTH_BOTTOM)[0]; Point2D<double> mouthLeft = features.getFeature(Feature::FEATURE_MOUTH_CORNER_LEFT)[0]; Point2D<double> mouthRight = features.getFeature(Feature::FEATURE_MOUTH_CORNER_RIGHT)[0]; //This (weird) method can be used to draw a debug line HereBeDragons::ButRisingAtThyNameDothPointOutThee(*debug, mouthLeft, mouthRight, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, mouthTop, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, mouthBottom, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, mouthLeft, colorRed); HereBeDragons::TriumphInLoveFleshStaysNoFatherReason(*debug, mouthRight, colorRed); ImageIO::saveRGBImage(*debug, ImageIO::getDebugFileName("feature-points-debug.png")); delete debug; }
bool StudentLocalization::stepFindExactEyes(const IntensityImage &image, FeatureMap &features) const { int temp = 0; ImageIO::saveIntensityImage(image, ImageIO::getDebugFileName("input.png")); IntensityImageStudent copy(image); double** d_kern = new double*[3]; for (int y = 0; y < 3; y++) { d_kern[y] = new double[3]; } d_kern[0][0] = 0; d_kern[0][1] = 1; d_kern[0][2] = 0; d_kern[1][0] = 1; d_kern[1][1] = 0; d_kern[1][2] = 1; d_kern[2][0] = 0; d_kern[2][1] = 1; d_kern[2][2] = 0; StudentKernel dilation = StudentKernel(d_kern, 3, 3, 0); Feature top = features.getFeature(Feature::FEATURE_HEAD_TOP); Feature bottom = features.getFeature(Feature::FEATURE_CHIN); Feature nose_bottom = features.getFeature(Feature::FEATURE_NOSE_BOTTOM); Feature headsideleft = features.getFeature(Feature::FEATURE_HEAD_LEFT_SIDE); Feature headsideright = features.getFeature(Feature::FEATURE_HEAD_RIGHT_SIDE); const int nose_to_top = nose_bottom.getY() - top.getY(); #if UNNECESSARY_CODE #endif Point2D<double> headsidelp = headsideleft.getPoints()[0]; headsidelp.setY(top.getY() + (nose_to_top*3/5)); headsidelp.setX((headsidelp.getX())); Point2D<double> headsiderp = headsideright.getPoints()[0]; headsiderp.setY(nose_bottom.getY() - (nose_to_top*1/5)); headsiderp.setX((headsiderp.getX() + 3)); IntensityImageStudent eyes = ImageUtils::subimage(&image, headsidelp, headsiderp); IntensityImageStudent eyes_dilated = dilation.dilate(&eyes); StudentHistogram histo{eyes_dilated.getWidth()}; int zero_points[2] = { 0, histo.get_length() * 1 / 7 }; int lowest_found[2] = { eyes_dilated.getHeight(), eyes_dilated.getHeight() }; int left_out = 0, left_out_x = 0, right_out = 0, right_out_x = 0, left_in = 0, left_in_x = 0, right_in = 0, right_in_x = 0; for (int x = 0; x < histo.get_length(); x++){ temp = 0; for (int y = 0; y < eyes_dilated.getHeight(); y++){ temp += eyes_dilated.getPixel(x, y) > 127 ? 0 : 1; } histo.set_value(x, temp); if (x < histo.get_length() * 3 / 10 && temp <= lowest_found[0]){ lowest_found[0] = temp; zero_points[0] = x; } if (x > histo.get_length() * 7 / 10 && temp < lowest_found[1]){ lowest_found[1] = temp; zero_points[1] = x; } } headsidelp.setX(headsidelp.getX() + zero_points[0]); headsiderp.setX(headsiderp.getX() - (histo.get_length() - zero_points[1])); headsidelp.setY(top.getY() + (nose_to_top * 2/ 5)); headsiderp.setY(nose_bottom.getY()); IntensityImageStudent eyes2(ImageUtils::subimage(&image, headsidelp, headsiderp)); IntensityImageStudent eyes_copy2(dilation.dilate(&eyes2)); histo.cut_to_size(zero_points[0], zero_points[1]); for (int x = 0; x < histo.get_length(); x++){ if (x < histo.get_length() * 2 / 9){ left_out_x = histo.get_value(x) > left_out ? x : left_out_x; left_out = histo.get_value(x) > left_out ? histo.get_value(x) : left_out; } else if (x < histo.get_length() * 4 / 9 && x > histo.get_length() * 2 / 9){ left_in_x = histo.get_value(x) > left_in ? x : left_in_x; left_in = histo.get_value(x) > left_in ? histo.get_value(x) : left_in; } else if (x > histo.get_length() * 7 / 9){ right_out_x = histo.get_value(x) > right_out ? x : right_out_x; right_out = histo.get_value(x) > right_out ? histo.get_value(x) : right_out; } else if (x > histo.get_length() * 5 / 9){ right_in_x = histo.get_value(x) > right_in ? x : right_in_x; right_in = histo.get_value(x) > right_in ? histo.get_value(x) : right_in; } } int forehead_val = 10, forehead_y = 0; StudentHistogram histo2{eyes_copy2.getHeight()}; for (int y = 0; y < histo2.get_length(); y++){ temp = 0; for (int x = 0; x < eyes_copy2.getWidth(); x++){ temp += eyes_copy2.getPixel(x, y) > 127 ? 0 : 1; } histo2.set_value(y, temp); } for (int y = 0; y < histo2.get_length(); y++){ if (histo2.get_value(y) <= forehead_val){ forehead_val = histo2.get_value(y); forehead_y = y; } else if (histo2.get_value(y) > 35 && forehead_val != 10) break; } headsidelp.setY(top.getY() + (nose_to_top * 2 / 5) + forehead_y); forehead_val = 15, forehead_y = histo2.get_length() -1; for (int y = histo2.get_length() -1; y > 0; --y){ if (histo2.get_value(y) <= forehead_val){ forehead_val = histo2.get_value(y); forehead_y = y; } else if (histo2.get_value(y) > 40 && forehead_val != 15) break; } headsiderp.setY(nose_bottom.getY() - (histo2.get_length() - forehead_y + 4)); Point2D<double> precise_ref{headsidelp}; IntensityImageStudent eyes3(ImageUtils::subimage(&image, headsidelp, headsiderp)); IntensityImageStudent eyes_copy3(dilation.dilate(&eyes3)); #ifdef DEBUG ImageIO::saveIntensityImage(eyes2, ImageIO::getDebugFileName("first eye cut.png")); ImageIO::saveIntensityImage(eyes_copy3, ImageIO::getDebugFileName("subimage_test3.png")); #endif // DEBUG StudentHistogram histo4{ eyes_copy3.getHeight() }; for (int y = 0; y < histo4.get_length(); y++){ temp = 0; for (int x = 0; x < eyes_copy3.getWidth(); x++){ temp += eyes_copy3.getPixel(x, y) > 127 ? 0 : 1; } histo4.set_value(y, temp); } #ifdef DEBUG ImageIO::saveIntensityImage(*histo2.get_debug_image(), ImageIO::getDebugFileName("histo2.png")); #endif // DEBUG int step = 0, bottom_eye_y = headsiderp.getY(), top_eye_y = headsidelp.getY() +10; for (int y = histo4.get_length(); y > 0; --y){ if (step == 0 && histo4.get_value(y) > 30){ bottom_eye_y = y; step++; } if (step == 1 && histo4.get_value(y) < histo4.get_value(bottom_eye_y)){ top_eye_y = y; break; } } IntensityImageStudent eyes_precise{eyes3}; for (int x = 0; x < eyes_precise.getWidth(); x++){ eyes_precise.setPixel(x, top_eye_y, 127); eyes_precise.setPixel(x, bottom_eye_y + 2, 127); } for (int y = 0; y < eyes_precise.getHeight(); y++){ eyes_precise.setPixel(left_in_x, y, 127); eyes_precise.setPixel(right_in_x, y, 127); eyes_precise.setPixel(left_out_x, y, 127); eyes_precise.setPixel(right_out_x, y, 127); } bottom_eye_y += 2; IntensityImageStudent eyes_precise2 = ImageUtils::subimage( &eyes_precise, Point2D<double>{0.0, (double)(top_eye_y)}, Point2D<double>{(double)eyes_precise.getWidth(), (double)bottom_eye_y} ); #ifdef DEBUG ImageIO::saveIntensityImage(eyes_precise2, ImageIO::getDebugFileName("eyes_precise.png")); ImageIO::saveIntensityImage(*histo.get_debug_image(), ImageIO::getDebugFileName("histo.png")); #endif // DEBUG StudentHistogram histoTopBottom{eyes_precise2.getWidth()}; for (int i = 0; i < histoTopBottom.get_length(); i++){ temp = 0; for (int j = 0; j < eyes_precise2.getHeight(); j++){ temp += eyes_precise2.getPixel(i, j) > 127? 0: 1; } histoTopBottom.set_value(i, temp); } #ifdef DEBUG ImageIO::saveIntensityImage(*histoTopBottom.get_debug_image(), ImageIO::getDebugFileName("histo.png")); #endif // DEBUG int outsideLeftX = 0, insideLeftX = 0, insideRightX = 0, outsideRightX = histoTopBottom.get_length()-1; for (int i = 0; i < histoTopBottom.get_length(); i++){ if (histoTopBottom.get_value(i) > eyes_precise2.getHeight() / 2 && i < histoTopBottom.get_length()*1/4){ outsideLeftX = i; i = histoTopBottom.get_length() * 1 / 4; } else if (histoTopBottom.get_value(i) < eyes_precise2.getHeight() / 3 && i < histoTopBottom.get_length() / 2 && i > histoTopBottom.get_length() * 1 / 4){ insideLeftX = i; i = histoTopBottom.get_length() / 2; } else if (histoTopBottom.get_value(i) > eyes_precise2.getHeight() / 2 && i < histoTopBottom.get_length() * 3 / 4 && i > histoTopBottom.get_length() / 2){ insideRightX = i; i = histoTopBottom.get_length() * 3 / 4; } else if (histoTopBottom.get_value(i) < eyes_precise2.getHeight() / 3 && i > histoTopBottom.get_length() * 3 / 4){ outsideRightX = i; break; } } #ifdef DEBUG IntensityImageStudent eyes_precise21 = ImageUtils::subimage(&eyes_precise, Point2D<double>{(double)outsideLeftX, (double)(top_eye_y)}, Point2D<double>{(double)insideLeftX, (double)bottom_eye_y}); ImageIO::saveIntensityImage(eyes_precise21, ImageIO::getDebugFileName("left_eye.png")); IntensityImageStudent eyes_precise22 = ImageUtils::subimage(&eyes_precise, Point2D<double>{(double)insideRightX, (double)(top_eye_y)}, Point2D<double>{(double)outsideRightX, (double)bottom_eye_y}); ImageIO::saveIntensityImage(eyes_precise22, ImageIO::getDebugFileName("right_eye.png")); #endif Feature left = Feature(Feature::FEATURE_EYE_LEFT_RECT); Feature right = Feature(Feature::FEATURE_EYE_RIGHT_RECT); left.addPoint(precise_ref + Point2D<double>{(double)outsideLeftX, (double)(top_eye_y)}); left.addPoint(precise_ref + Point2D<double>{(double)insideLeftX, (double)bottom_eye_y}); right.addPoint(precise_ref + Point2D<double>{(double)insideRightX, (double)(top_eye_y)}); right.addPoint(precise_ref + Point2D<double>{(double)outsideRightX, (double)bottom_eye_y}); features.putFeature(right); features.putFeature(left); for (int y = 0; y < 3; y++) { delete[] d_kern[y]; } delete[] d_kern; return true; }
bool StudentExtraction::stepExtractMouth(const IntensityImage &image, FeatureMap &features) const { std::cout << "has FEATURE_MOUTH_CENTER " << features.getFeature(Feature::FEATURE_MOUTH_CENTER).getY() << std::endl; std::cout << "has FEATURE_MOUTH_BOTTOM " << features.getFeature(Feature::FEATURE_MOUTH_BOTTOM).getY() << std::endl; std::cout << "has FEATURE_MOUTH_TOP " << features.getFeature(Feature::FEATURE_MOUTH_TOP).getY() << std::endl; return false; }
bool StudentLocalization::stepFindChinContours(const IntensityImage &image, FeatureMap &features) const { // Maak een basetimer object om de tijd bij te houden dat de implementatie nodig heeft. BaseTimer basetimer; // Start de basetimer. basetimer.start(); // test getal int startStep = 15; bool first = true; // Sla het middenpunt van de mond op. Point2D<double> MouthCenterPoint = features.getFeature(Feature::FEATURE_MOUTH_CENTER).getPoints()[0]; // Sla het kin punt op. Point2D<double> ChinPoint = features.getFeature(Feature::FEATURE_CHIN).getPoints()[0]; int range = MouthCenterPoint.getY() - ChinPoint.getY(); // Object om kincountoer punten in op te slaan. Feature output = Feature(Feature::FEATURE_CHIN_CONTOUR); int degrees; int steps = 15; int lastdif; double correction = -1; int lastSteps = 0; int vorigeX = 0; // Bereken 20 punten van de kin. for (int i = 0; i < 19; i++) { bool ireg = false; if (i>9) { correction = 1; } else if (i < 9) { correction =0; } // Sla middelpunt mond x op. int checkX = MouthCenterPoint.getX(); // Sla middelpunt mond y op. int checkY = MouthCenterPoint.getY(); double gradenInRad = (-90+(i * 10)) *(PI/180); steps = startStep; Point2D<double> gevondenPunt; // Middelste punt van de kin is als het goed is bekend. Dit is punt nummer 9 dus zal worden overgeslagen. if (i != 9) { while (true) { if (!first&&steps > startStep + 10) { lastdif / i; ireg = true; gevondenPunt.set(MouthCenterPoint.getX() + ((lastSteps + correction)* std::sin(gradenInRad)), MouthCenterPoint.getY() + ((lastSteps + correction) * std::cos(gradenInRad))); steps = lastSteps + correction; break; } checkX = MouthCenterPoint.getX()+ (steps * std::sin(gradenInRad)); checkY = MouthCenterPoint.getY()+(steps * std::cos(gradenInRad)); Intensity pixel = image.getPixel(std::round(checkX), std::round(checkY)); if (int(pixel) == 0) { if (checkX - vorigeX <2) { lastdif / i; ireg = true; gevondenPunt.set(MouthCenterPoint.getX() + ((lastSteps + correction)* std::sin(gradenInRad)), MouthCenterPoint.getY() + ((lastSteps + correction) * std::cos(gradenInRad))); steps = lastSteps + correction; break; } ireg=false; gevondenPunt.set(checkX, checkY); break; } steps++; } vorigeX = checkX; std::cout << gevondenPunt <<"\n"; startStep = steps - 5; output.addPoint(Point2D<double>(gevondenPunt.x,gevondenPunt.y)); first=false; if (ireg) { startStep = steps-5; lastSteps = steps; } else { lastdif = lastSteps - steps; lastSteps = steps; } } else { output.addPoint(ChinPoint); } } features.putFeature(output); basetimer.stop(); std::ofstream myfile; myfile.open("tijd.txt", std::ofstream::ate); myfile << "Chincontours convert tijd in s: " << basetimer.elapsedSeconds() << " tijd ms:" << basetimer.elapsedMilliSeconds() << " tijd us" << basetimer.elapsedMicroSeconds(); myfile.close(); return true; }