// use k-means to reduce color number MyQuantifiedImage* kmeansQuantification(IplImage* img, int tableSize) { // step 1: transfer image to kmeans samples int sample_count = img->height * img->width; CvMat* samples = cvCreateMat(sample_count, 1, CV_32FC3); CvRNG rng = cvRNG(0xffffffff); int idx = 0; for (int i = 0; i < img->height; i++) { for (int j = 0; j < img->width; j++) { cvSet1D(samples, idx++, cvGet2D(img, i, j)); } } // step 2: apply kmeans; CvMat* labels = cvCreateMat(sample_count, 1, CV_32SC1); CvMat* centers = cvCreateMat(tableSize, 1, CV_32FC3); cvSetZero(labels); cvSetZero(centers); cvKMeans2(samples, tableSize, labels, cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 10, CV_KMEANS_ACC), CV_KMEANS_ATTEMPTS, &rng, CV_KMEANS_PP_CENTERS, centers, 0); // flag = KMEANS_PP_CENTERS // step 3: rebuild the image IplImage* quantImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_32F, 3); CvMat* labelImg = cvCreateMat(img->height, img->width, CV_32SC1); cvSetZero(quantImg); cvSetZero(labelImg); idx = 0; for (int i = 0; i < img->height; i++) { for (int j = 0; j < img->width; j++) { int cluster_idx = labels->data.i[idx++]; CvScalar color = cvGet1D(centers, cluster_idx); cvSet2D(quantImg, i, j, color); cvSetReal2D(labelImg, i, j, (double) cluster_idx); } } MyQuantifiedImage* re = malloc(sizeof(MyQuantifiedImage)); re->labelMat = labelImg; re->qImg = quantImg; re->tableSize = tableSize; CvScalar* colorTable = calloc(tableSize, sizeof(CvScalar)); for (int i = 0; i < tableSize; i++) { colorTable[i] = cvGet1D(centers, i); } re->colorTable = colorTable; return re; }
/** * Method for summing all the rows in a vector to a value of type double. * * @param src A pointer to a vector to be summed. * * @return Returns sum of all rows in a vector as a double. */ double LibFaceUtils::sumVecToDouble(CvMat* src) { double sum = 0; int i; for (i = 0; i < src->rows; ++i) { sum = sum + cvGet1D(src, i).val[0]; } return sum; }
/** * A method for adding another element to the end of a vector. * * @param src A pointer to a matrix. * @param value Value to be appended to the end. * * @return Returns a pointer to the new vector. */ CvMat* LibFaceUtils::addScalar(CvMat* src, CvScalar value) { CvMat* result = cvCreateMat(src->rows+1,1,src->type); int i; for (i=0 ; i < src->rows ; ++i) { cvSet1D(result, i, cvGet1D(src, i)); } cvSet1D(result, src->rows,value); return result; }
/** * A method for subtrating a vector from a matrix. New matrix is created in process. * * @param src1 A pointer to a matrix to be subtracted from. * @param src2 A pointer to a vector to be subtracted. * * @return Returns a pointer to the new matrix. */ CvMat* LibFaceUtils::subtract(CvMat* src1, CvMat* src2) { int i, j; CvMat* result = cvCreateMat(src1->rows, src1->cols, src1->type); for (i = 0 ; i < src1->rows ; ++i) { for (j=0 ; j < src1->cols ; ++j) { double value1 = cvGet2D(src1, i, j).val[0]; double value2 = cvGet1D(src2, i).val[0]; double res = value1 - value2; cvSet2D(result, i, j, cvScalarAll(res)); } } return result; }
/** * Method for adding an extra column to a matrix. This method makes no checks on validity * of the data. * * @param src A pointer to a matrix to be added to. * @param vector A pointer to a vector to be added to the matrix. Needs to have the same number of rows. * * @return Returns a pointer to the new matrix with added column. */ CvMat* LibFaceUtils::combine(CvMat* src, CvMat* vector) { int i, j; CvMat* result = cvCreateMat(src->rows, src->cols + 1, src->type); for (i = 0; i < src->rows; ++i) { for (j = 0; j <= src->cols; ++j) { if (j != src->cols) cvSet2D(result, i, j, cvGet2D(src, i, j)); else cvSet2D(result, i, j, cvGet1D(vector, i)); } } return result; }
void cveGet1D(CvArr* arr, int idx0, CvScalar* value) { *value = cvGet1D(arr, idx0); }
int main() { IplImage* img = cvLoadImage("goal_arena.bmp"); CvSize imgSize = cvGetSize(img); IplImage* detected = cvCreateImage(imgSize, 8, 1); IplImage* imgBlue = cvCreateImage(imgSize, 8, 1); IplImage* imgGreen = cvCreateImage(imgSize, 8, 1); IplImage* imgRed = cvCreateImage(imgSize, 8, 1); cvSplit(img, imgBlue, imgGreen, imgRed, NULL); cvAnd(imgGreen, imgBlue, detected); cvAnd(detected, imgRed, detected); cvErode(detected, detected); cvDilate(detected, detected); // Opening // cvThreshold(detected, detected, 100, 250, CV_THRESH_BINARY); CvMat* lines = cvCreateMat(100, 1, CV_32FC2); cvHoughLines2(detected, lines, CV_HOUGH_STANDARD, 1, 0.001, 100); // CvMat* lines = cvCreateMat(100, 1, CV_32FC2); // cvHoughLines2(detected, lines, CV_HOUGH_STANDARD, 1, 0.001, 100); CvPoint left1 = cvPoint(0, 0); CvPoint left2 = cvPoint(0, 0); CvPoint right1 = cvPoint(0, 0); CvPoint right2 = cvPoint(0, 0); CvPoint top1 = cvPoint(0, 0); CvPoint top2 = cvPoint(0, 0); CvPoint bottom1 = cvPoint(0, 0); CvPoint bottom2 = cvPoint(0, 0); int numLines = lines->rows; int numTop = 0; int numBottom = 0; int numLeft = 0; int numRight = 0; for(int i=0;i<numLines;i++) { CvScalar dat = cvGet1D(lines, i); double rho = dat.val[0]; double theta = dat.val[1]; if(theta==0.0) continue; double degrees = theta*180.0/(3.1412); CvPoint pt1 = cvPoint(0, rho/sin(theta)); CvPoint pt2 = cvPoint(img->width, (-img->width/tan(theta)) + rho/sin(theta)); if(abs(rho)<50.0) { if(degrees>45.0 && degrees<135.0) { numTop++; // The line is vertical and near the top top1.x+=pt1.x; top1.y+=pt1.y; top2.x+=pt2.x; top2.y+=pt2.y; } else { numLeft++; // The line is vertical and near the left left1.x+=pt1.x; left1.y+=pt1.y; left2.x+=pt2.x; left2.y+=pt2.y; } } else { // We're in the right portion if(degrees>45.0 && degrees<135.0) { numBottom++; //The line is horizontal and near the bottom bottom1.x+=pt1.x; bottom1.y+=pt1.y; bottom2.x+=pt2.x; bottom2.y+=pt2.y; } else { numRight++; // The line is vertical and near the right right1.x+=pt1.x; right1.y+=pt1.y; right2.x+=pt2.x; right2.y+=pt2.y; } } } left1.x/=numLeft; left1.y/=numLeft; left2.x/=numLeft; left2.y/=numLeft; right1.x/=numRight; right1.y/=numRight; right2.x/=numRight; right2.y/=numRight; top1.x/=numTop; top1.y/=numTop; top2.x/=numTop; top2.y/=numTop; bottom1.x/=numBottom; bottom1.y/=numBottom; bottom2.x/=numBottom; bottom2.y/=numBottom; cvLine(img, left1, left2, CV_RGB(255, 0,0), 1); cvLine(img, right1, right2, CV_RGB(255, 0,0), 1); cvLine(img, top1, top2, CV_RGB(255, 0,0), 1); cvLine(img, bottom1, bottom2, CV_RGB(255, 0,0), 1); // Next, we need to figure out the four intersection points double leftA = left2.y-left1.y; double leftB = left1.x-left2.x; double leftC = leftA*left1.x + leftB*left1.y; double rightA = right2.y-right1.y; double rightB = right1.x-right2.x; double rightC = rightA*right1.x + rightB*right1.y; double topA = top2.y-top1.y; double topB = top1.x-top2.x; double topC = topA*top1.x + topB*top1.y; double bottomA = bottom2.y-bottom1.y; double bottomB = bottom1.x-bottom2.x; double bottomC = bottomA*bottom1.x + bottomB*bottom1.y; // Intersection of left and top double detTopLeft = leftA*topB - leftB*topA; CvPoint ptTopLeft = cvPoint((topB*leftC - leftB*topC)/detTopLeft, (leftA*topC - topA*leftC)/detTopLeft); // Intersection of top and right double detTopRight = rightA*topB - rightB*topA; CvPoint ptTopRight = cvPoint((topB*rightC-rightB*topC)/detTopRight, (rightA*topC-topA*rightC)/detTopRight); // Intersection of right and bottom double detBottomRight = rightA*bottomB - rightB*bottomA; CvPoint ptBottomRight = cvPoint((bottomB*rightC-rightB*bottomC)/detBottomRight, (rightA*bottomC-bottomA*rightC)/detBottomRight); // Intersection of bottom and left double detBottomLeft = leftA*bottomB-leftB*bottomA; CvPoint ptBottomLeft = cvPoint((bottomB*leftC-leftB*bottomC)/detBottomLeft, (leftA*bottomC-bottomA*leftC)/detBottomLeft); cvLine(img, ptTopLeft, ptTopLeft, CV_RGB(0,255,0), 5); cvLine(img, ptTopRight, ptTopRight, CV_RGB(0,255,0), 5); cvLine(img, ptBottomRight, ptBottomRight, CV_RGB(0,255,0), 5); cvLine(img, ptBottomLeft, ptBottomLeft, CV_RGB(0,255,0), 5); IplImage* imgMask = cvCreateImage(imgSize, 8, 3); cvZero(imgMask); CvPoint* pts = new CvPoint[4]; pts[0] = ptTopLeft; pts[1] = ptTopRight; pts[2] = ptBottomRight; pts[3] = ptBottomLeft; cvFillConvexPoly(imgMask, pts, 4, cvScalar(255,255,255)); cvAnd(img, imgMask, img); cvNamedWindow("Original"); cvNamedWindow("Detected"); cvShowImage("Original", img); cvShowImage("Detected", detected); cvWaitKey(0); return 0; }
int main() { // Load the image we'll work on IplImage* img = cvLoadImage("C:\\goal_arena.jpg"); CvSize imgSize = cvGetSize(img); // This will hold the white parts of the image IplImage* detected = cvCreateImage(imgSize, 8, 1); // These hold the three channels of the loaded image IplImage* imgBlue = cvCreateImage(imgSize, 8, 1); IplImage* imgGreen = cvCreateImage(imgSize, 8, 1); IplImage* imgRed = cvCreateImage(imgSize, 8, 1); cvSplit(img, imgBlue, imgGreen, imgRed, NULL); // Extract white parts into detected cvAnd(imgGreen, imgBlue, detected); cvAnd(detected, imgRed, detected); // Morphological opening cvErode(detected, detected); cvDilate(detected, detected); // Thresholding (I knew you wouldn't catch this one... so i wrote a comment here // I mean the command can be so decieving at times) cvThreshold(detected, detected, 100, 250, CV_THRESH_BINARY); // Do the hough thingy CvMat* lines = cvCreateMat(100, 1, CV_32FC2); cvHoughLines2(detected, lines, CV_HOUGH_STANDARD, 1, 0.001, 100); // The two endpoints for each boundary line CvPoint left1 = cvPoint(0, 0); CvPoint left2 = cvPoint(0, 0); CvPoint right1 = cvPoint(0, 0); CvPoint right2 = cvPoint(0, 0); CvPoint top1 = cvPoint(0, 0); CvPoint top2 = cvPoint(0, 0); CvPoint bottom1 = cvPoint(0, 0); CvPoint bottom2 = cvPoint(0, 0); // Some numbers we're interested in int numLines = lines->rows; int numTop = 0; int numBottom = 0; int numLeft = 0; int numRight = 0; // Iterate through each line for(int i=0;i<numLines;i++) { // Get the parameters for the current line CvScalar dat = cvGet1D(lines, i); double rho = dat.val[0]; double theta = dat.val[1]; if(theta==0.0) { // This is an obviously vertical line... and we can't approximate it... NEXT continue; } // Convert from radians to degrees double degrees = theta*180/(3.1412); // Generate two points on this line (one at x=0 and one at x=image's width) CvPoint pt1 = cvPoint(0, rho/sin(theta)); CvPoint pt2 = cvPoint(img->width, (-img->width/tan(theta)) + rho/sin(theta)); if(abs(rho)<50) // Top + left { if(degrees>45 && degrees<135) // Top { numTop++; // The line is horizontal and near the top top1.x+=pt1.x; top1.y+=pt1.y; top2.x+=pt2.x; top2.y+=pt2.y; } else // left { numLeft++; //The line is vertical and near the left left1.x+=pt1.x; left1.y+=pt1.y; left2.x+=pt2.x; left2.y+=pt2.y; } } else // bottom+right { if(degrees>45 && degrees<135) // Bottom { numBottom++; //The line is horizontal and near the bottom bottom1.x+=pt1.x; bottom1.y+=pt1.y; bottom2.x+=pt2.x; bottom2.y+=pt2.y; } else // Right { numRight++; // The line is vertical and near the right right1.x+=pt1.x; right1.y+=pt1.y; right2.x+=pt2.x; right2.y+=pt2.y; } } } // we've done the adding... now the dividing to get the "averaged" point left1.x/=numLeft; left1.y/=numLeft; left2.x/=numLeft; left2.y/=numLeft; right1.x/=numRight; right1.y/=numRight; right2.x/=numRight; right2.y/=numRight; top1.x/=numTop; top1.y/=numTop; top2.x/=numTop; top2.y/=numTop; bottom1.x/=numBottom; bottom1.y/=numBottom; bottom2.x/=numBottom; bottom2.y/=numBottom; // Render these lines onto the image cvLine(img, left1, left2, CV_RGB(255, 0,0), 1); cvLine(img, right1, right2, CV_RGB(255, 0,0), 1); cvLine(img, top1, top2, CV_RGB(255, 0,0), 1); cvLine(img, bottom1, bottom2, CV_RGB(255, 0,0), 1); // Next, we need to figure out the four intersection points double leftA = left2.y-left1.y; double leftB = left1.x-left2.x; double leftC = leftA*left1.x + leftB*left1.y; double rightA = right2.y-right1.y; double rightB = right1.x-right2.x; double rightC = rightA*right1.x + rightB*right1.y; double topA = top2.y-top1.y; double topB = top1.x-top2.x; double topC = topA*top1.x + topB*top1.y; double bottomA = bottom2.y-bottom1.y; double bottomB = bottom1.x-bottom2.x; double bottomC = bottomA*bottom1.x + bottomB*bottom1.y; // Intersection of left and top double detTopLeft = leftA*topB - leftB*topA; CvPoint ptTopLeft = cvPoint((topB*leftC - leftB*topC)/detTopLeft, (leftA*topC - topA*leftC)/detTopLeft); // Intersection of top and right double detTopRight = rightA*topB - rightB*topA; CvPoint ptTopRight = cvPoint((topB*rightC-rightB*topC)/detTopRight, (rightA*topC-topA*rightC)/detTopRight); // Intersection of right and bottom double detBottomRight = rightA*bottomB - rightB*bottomA; CvPoint ptBottomRight = cvPoint((bottomB*rightC-rightB*bottomC)/detBottomRight, (rightA*bottomC-bottomA*rightC)/detBottomRight); // Intersection of bottom and left double detBottomLeft = leftA*bottomB-leftB*bottomA; CvPoint ptBottomLeft = cvPoint((bottomB*leftC-leftB*bottomC)/detBottomLeft, (leftA*bottomC-bottomA*leftC)/detBottomLeft); // Render the points onto the image cvLine(img, ptTopLeft, ptTopLeft, CV_RGB(0,255,0), 5); cvLine(img, ptTopRight, ptTopRight, CV_RGB(0,255,0), 5); cvLine(img, ptBottomRight, ptBottomRight, CV_RGB(0,255,0), 5); cvLine(img, ptBottomLeft, ptBottomLeft, CV_RGB(0,255,0), 5); // Initialize a mask IplImage* imgMask = cvCreateImage(imgSize, 8, 3); cvZero(imgMask); // Generate the mask CvPoint* pts = new CvPoint[4]; pts[0] = ptTopLeft; pts[1] = ptTopRight; pts[2] = ptBottomRight; pts[3] = ptBottomLeft; cvFillConvexPoly(imgMask, pts, 4, cvScalar(255,255,255)); // Delete anything thats outside the mask cvAnd(img, imgMask, img); // Show all images in windows cvNamedWindow("Original"); cvNamedWindow("Detected"); cvShowImage("Original", img); cvShowImage("Detected", detected); cvWaitKey(0); return 0; }