0
votes

I want to detect the squares of pictures, but I am having problems when calculating the amount of the existing squares. In the picture there are 6 piece of squares, but there are 8 pieces that were detected, 3 of which were detected twice.

This is the result of image detection http://i698.photobucket.com/albums/vv347/holybring18/Screenshot_2013-11-01-07-37-17.png

this is the preprocess http://i698.photobucket.com/albums/vv347/holybring18/Screenshot_2013-11-01-07-37-49.png

this is my code, i got from squares.cpp example code. I code this in my Android with native language, so everything about squares detection is handled by my native code. But i modified a little Because there was an annoying error at mixChannels () that i do not know how to fix it.

// jlong from java convert to references to Mat
// for image source and image result
Mat& matsrc = *(Mat*)alamatMatSrc;
Mat& matres = *(Mat*)alamatMatRes;

// needed matrix
Mat gray;
Mat blur;
Mat bw;
Mat dil;
Mat er;

// tempat menyimpan kontur dan estimasi sudut
vector<vector<Point> > squares;
vector<vector<Point> > contours;
vector<Point> approx;

// convert to grayscale
cvtColor(matsrc, gray, CV_BGR2GRAY);

// blur for reducing noise
medianBlur(gray, blur, 9);

// edge detection with Canny
Canny(blur, bw, 0, 50);

// dilate to ensure there is no cut off lines
dilate(bw, dil, Mat(), Point(-1,-1));

// find all contours
findContours(dil, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

// loop to find the squares
for (size_t i = 0; i < contours.size(); i++) {

    // approximate contour with accuracy proportional
    // to the contour perimeter
    approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

    // Note: absolute value of an area is used because
    // area may be positive or negative - in accordance with the
    // contour orientation
    if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) {
        double maxCosine = 0;

        for (int j = 2; j < 5; j++) {
            Point pt1 = approx[j%4];
            Point pt2 = approx[j-2];
            Point pt3 = approx[j-1];
            double cosine = fabs(sudut(pt1, pt2, pt3));
            maxCosine = MAX(maxCosine, cosine);
            }
        if (maxCosine < 0.1) squares.push_back(approx);
    }
}

And this is the my java code when invoking the native

// provide Mat for the source and for the result
mymatsrc = new Mat(mybmp.getWidth(), mybmp.getHeight(), CvType.CV_8UC1);
mymatres = new Mat(mybmp.getWidth(), mybmp.getHeight(), CvType.CV_8UC1);

// convert bitmap to Mat, then pass the Mat adress to native, process, and convert it again to bitmap
Utils.bitmapToMat(mybmp, mymatsrc);
Utils.bitmapToMat(mybmp, mymatres);
preProcess(mymatsrc.getNativeObjAddr(), mymatres.getNativeObjAddr());
Utils.matToBitmap(mymatres, mybmp);

// show the processed picture
imageView.setImageBitmap(mybmp);

My point is:

  1. why my code detected square more than it should be?
  2. how do I fix this?
  3. I found a few people experiencing errors on mixChannel () and i can not find the solution, is anyone knows how to fix this, this is the error message.

Invalid arguments ' Candidates are: void mixChannels(const cv::Mat *, ?, cv::Mat *, ?, const int *, ?) void mixChannels(const cv::_InputArray &, const cv::_InputArray &, const std::vector> &) void mixChannels(const std::vector> &, std::vector> &, const int *, ?) '

1
Pls include your mixChannels() call, otherwise it is impossible to know what is wrongBull
i'm sorry, but it is exactly the same as the sample, squares.cpp, this is the guy who has the same problem, and still no one can answer it answers.opencv.org/question/17568/opencv-mixchannelslittledeveloper
that compiles fine with OpenCV 2.4.4 and VS 2013. It seems either your compiler or your OpenCV install is broken - what are you using?Bull

1 Answers

0
votes
  1. Because of the kernel size for medianBlur() is 9 pixels.

  2. Reduce the kernel size to 3 or 5.

  3. See mixChannels() documentation

From squares.cpp

// find squares in every color plane of the image
for( int c = 0; c < 3; c++ )
{
    int ch[] = {c, 0};
    mixChannels(&timg, 1, &gray0, 1, ch, 1);

The dst gray0 must be preallocated. On each iteratation, the channel specified by c is copied from timg into gray0.