IntensityImage * ImageFactory::newIntensityImage(const IntensityImage &other) { IntensityImage * image = ImageFactory::newIntensityImage(other.getWidth(), other.getHeight()); int size = other.getHeight() * other.getWidth(); for (int i = 0; i < size; i++) { image->setPixel(i, other.getPixel(i)); } return image; }
IntensityImageStudent::IntensityImageStudent(const IntensityImage &other) : IntensityImage(other.getWidth(), other.getHeight()), pixelMap(nullptr) { const int SIZE = other.getSize(); if(SIZE > 0) { pixelMap = new Intensity[SIZE]; for(int i = 0; i < SIZE; i++) { pixelMap[i] = other.getPixel(i); } } }
int StudentLocalization::getTopOfHead(const IntensityImage &image){ for (int y = 0; y < image.getHeight(); y++){ for (int x = 0; x < image.getWidth(); x++) { if (image.getPixel(x, y) == 0){ return y; } } } return -1; }
void IntensityImageStudent::set(const IntensityImage &other) { const int SIZE = other.getSize(); IntensityImage::set(other.getWidth(), other.getHeight()); if (SIZE > 0) { delete[] pixelMap; pixelMap = new Intensity[SIZE]; for (int i = 0; i < SIZE; i++) { pixelMap[i] = other.getPixel(i); } } }
void HereBeDragons::HerLoveForWhoseDearLoveIRiseAndFall(const IntensityImage &src, cv::Mat &dst) { int w = src.getWidth(); int h = src.getHeight(); dst.create(h, w, CV_8UC1); for (int x = 0; x < dst.cols; x++) { for (int y = 0; y < dst.rows; y++) { dst.at<uchar>(y, x) = src.getPixel(x, y); } } }
bool StudentLocalization::stepFindHead(const IntensityImage &image, FeatureMap &features) const { int yTop = getTopOfHead(image); int alpha = 13; int* histogram; int left, right; int diffFirstLast = -1, maxDiffFirstLast = -1; int ySides = -1; //number of slices the image will be 'cut' into for the histograms int count = ((image.getHeight() - yTop - 1) / alpha) + 1; for (int i = 0; i < count; i++) { //get histogram of current slice histogram = getHistogramX(image, alpha, yTop + i * alpha); findSidesInHistogram(histogram, image.getWidth(), &left, &right); //if no two sides have been found continue to the next slice if (left == -1 || right == -1) { continue; } //find the first peak gap between the left and right side to detect the position of the ears diffFirstLast = right - left; if (diffFirstLast > maxDiffFirstLast) { maxDiffFirstLast = diffFirstLast; } else { //if the gap is lower than the max, a peak has been found //and the y position of the ears will be set to the middle of the slice //where the peak is detected ySides = yTop + (i + 1) * alpha; break; } } //if no peak is detected return false if (ySides == -1) { return false; } //set the results in the feature map Point2D<double> * pointLeftSideHead = new Point2D<double>(left, ySides); Feature * leftSideHead = new Feature(Feature::FEATURE_HEAD_LEFT_SIDE, *pointLeftSideHead); features.putFeature(*leftSideHead); Point2D<double> * pointRightSideHead = new Point2D<double>(right, ySides); Feature * rightSideHead = new Feature(Feature::FEATURE_HEAD_RIGHT_SIDE, *pointRightSideHead); features.putFeature(*rightSideHead); Point2D<double> * pointTopOfHead = new Point2D<double>((left + right) / 2, yTop); Feature * topOfHead = new Feature(Feature::FEATURE_HEAD_TOP, *pointTopOfHead); features.putFeature(*topOfHead); return true; }
void LuminosityAlgorithm::doAlgorithm(const RGBImage& input, IntensityImage& output) { // Check image size if (input.getWidth() != output.getWidth() || input.getHeight() != output.getHeight()) { output.set(input.getWidth(), input.getHeight()); } // Lunimosity Algorithm defined as // Gray = (Red * 0.2126 + Green * 0.7152 + Blue * 0.0722) for (int i = 0; i < input.getWidth()*input.getHeight(); i++) { RGB pixel = input.getPixel(i); output.setPixel(i, pixel.r * 0.2126 + pixel.g * 0.7152 + pixel.b * 0.0722); } }
void Test::RunCannyTest(const RGBImage* in) { Gaussian smoother; Sobel sobel; Canny canny; StudentPreProcessing converter; double sigma = 1.6; int kernelSize = 5; // Convert RGB to Intensity IntensityImage* grey = ImageFactory::newIntensityImage(in->getWidth(), in->getHeight()); grey = converter.stepToIntensityImage(*in); BaseTimer timer; int total = 0; for (int i = 0; i < 10; ++i) { timer.start(); /* Start of Canny */ // 1. Smooth Intensity with Gaussian IntensityImage* gaussian = ImageFactory::newIntensityImage(in->getWidth() - kernelSize, in->getHeight() - kernelSize); smoother.smoothImage(grey, gaussian, sigma, kernelSize); // 2. Find edges with Sobel (convolve X and Y separately for Canny) int sobelKernelSize = 3; IntensityImage* sobelX = ImageFactory::newIntensityImage(gaussian->getWidth() - sobelKernelSize, gaussian->getHeight() - sobelKernelSize); IntensityImage* sobelY = ImageFactory::newIntensityImage(gaussian->getWidth() - sobelKernelSize, gaussian->getHeight() - sobelKernelSize); sobel.filterXY(gaussian, sobelX, sobelY); // 3. Apply non-maximum suppresion IntensityImage* nonMaxSuppression = ImageFactory::newIntensityImage(sobelX->getWidth(), sobelX->getHeight()); canny.nonMaximumSurpression(sobelX, sobelY, nonMaxSuppression); // 4. Apply hysteresis threshold IntensityImage* hysteresisThreshold = ImageFactory::newIntensityImage(sobelX->getWidth(), sobelX->getHeight()); canny.threshold(nonMaxSuppression, hysteresisThreshold, 60, 70); timer.stop(); std::cout << timer.elapsedMilliSeconds() << " ms" << std::endl; total += timer.elapsedMilliSeconds(); timer.reset(); if (i == 9) ImageIO::saveIntensityImage(*hysteresisThreshold, ImageIO::getDebugFileName("Canny.png")); } std::cout << "Average time per Canny edge detection: " << (total / 10) << " ms" << std::endl; std::cout << "Press the X in the console window to exit program" << std::endl; }
IntensityImageStudent GaussianFilter::applyFilter(const IntensityImage &image) { IntensityImageStudent filteredImage = IntensityImageStudent(image.getWidth() - 2 * radius, image.getHeight() - 2 * radius); for (int y = 0; y < filteredImage.getHeight(); y++){ for (int x = 0; x < filteredImage.getWidth(); x++){ double filteredIntensity = 0.0; for (unsigned int i = 0; i < gaussKernel.size(); i++){ filteredIntensity += gaussKernel[i] * image.getPixel(x + (i % (2 * radius + 1)), y + i / (2 * radius + 1)); } filteredImage.setPixel(x, y, static_cast<Intensity>(filteredIntensity)); } } return filteredImage; }
void HereBeDragons::NoWantOfConscienceHoldItThatICall(const cv::Mat &source, IntensityImage &dst) { int type = source.type(); if (type != CV_8UC1) { // throw std::exception("OpenCV Mat source image not of type CV_8UC1!"); throw std::exception{}; } dst.set(source.cols, source.rows); for (int x = 0; x < source.cols; x++) { for (int y = 0; y < source.rows; y++) { dst.setPixel(x, y, source.at<uchar>(y, x)); } } }
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); }
SonnetXVIII HereBeDragons::YetWhoKnowsNotConscienceIsBornOfLove(const IntensityImage &Yet, const int Who, const int Knows, const int Not, const int Conscience){ SonnetXVIII Is(Conscience); int Born = 0; for (int y = Knows; y < (Knows + Conscience); y++){ for (int x = Who; x < (Who + Not); x++){ if (Yet.getPixel(x, y) == 0){ Is[Born]++; } } Born++; } return Is; }
SonnetXVIII HereBeDragons::LoveIsTooYoungToKnowWhatConscienceIs(const IntensityImage &Love, const int Is, const int Too, const int Young, const int To){ SonnetXVIII Know(Young); int What = 0; for (int x = Is; x < (Is + Young); x++){ for (int y = Too; y < (Too + To); y++){ if (Love.getPixel(x, y) == 0){ Know[What]++; } } What++; } return Know; }
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; }
bool StudentLocalization::stepFindHead(const IntensityImage &image, FeatureMap &features) const { Histogram AxisY(image, 50, 50, 0, 0, Axis::y); //determine top of the head int topHead = -1; for (int i = 0; i < AxisY.getSize(); ++i) { if (AxisY.getValue(i) > 2) { topHead = i; break; } } if (topHead == -1) { return false; } //determine sides int lastLeftX = -1; int lastRightX = -1; for (int y = topHead; y < image.getHeight(); y += 20) { Histogram layerX(image, 0, 0, y, (image.getHeight() - y - 20), Axis::x); //determine leftside of the head int leftX = -1; for (int i = 0; i < layerX.getSize(); ++i) { if (layerX.getValue(i) > 2) { leftX = i; break; } } //determine rightside of the head int rightX = -1; for (int i = layerX.getSize() - 1; i >= 0 ; --i) { if (layerX.getValue(i) > 2) { rightX = i; break; } } // if not both sides are found skip the rest of the loop if (leftX == -1 || rightX == -1) { continue; } int currentHeadWidth = rightX - leftX; int lastHeadWidth = lastRightX - lastLeftX; if (currentHeadWidth < lastHeadWidth) { Feature * headUpperBound = new Feature(Feature::FEATURE_HEAD_TOP, Point2D<double>(lastRightX - (currentHeadWidth / 2), topHead)); Feature * headLeftBound = new Feature(Feature::FEATURE_HEAD_LEFT_SIDE, Point2D<double>(lastLeftX, y)); Feature * headRightBound = new Feature(Feature::FEATURE_HEAD_RIGHT_SIDE, Point2D<double>(lastRightX, y)); features.putFeature(*headUpperBound); features.putFeature(*headLeftBound); features.putFeature(*headRightBound); return true; } lastLeftX = leftX; lastRightX = rightX; } return false; }
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::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; }