1

I'm stuck porting code from one of the answers from Python to C++ and I was hoping someone can help do that and also clarify a part of the process.

The answer I'm talking about - https://stackoverflow.com/a/11366549

I'm at the step where centroids are being sorted (one before the last). The code in question does the job, but I'm unsure how to get the same result using C++ without making the code much longer.

centroids = np.array(centroids,dtype = np.float32)
c = centroids.reshape((100,2))
c2 = c[np.argsort(c[:,1])]

b = np.vstack([c2[i*10:(i+1)*10][np.argsort(c2[i*10:(i+1)*10,0])] for i in xrange(10)])
bm = b.reshape((10,10,2))

The way I want to achieve this is doing following:

  • The initial centroids array is already sorted in a way (highest y value Point has the index 0, the lowest has 99), so I'd like to invert it, making the array sorted top to bottom.

  • After that it's just a matter of sorting through rows (sorting 10 rows with 10 columns by x axis)

I believe that's all that has to be done, but I cannot find an elegant way to code this (without using vector, and sorting manually).

I also don't quite understand the last step, where the image is being warped (making it hard to port), so if anyone could provide some insight as to what's being done in this part and possibly C++ equivalent to this, I'd appreciate it.

output = np.zeros((450,450,3),np.uint8)
for i,j in enumerate(b):
    ri = i/10
    ci = i%10
    if ci != 9 and ri!=9:
        src = bm[ri:ri+2, ci:ci+2 , :].reshape((4,2))
        dst = np.array( [ [ci*50,ri*50],[(ci+1)*50-1,ri*50],[ci*50,(ri+1)*50-1],[(ci+1)*50-1,(ri+1)*50-1] ], np.float32)
        retval = cv2.getPerspectiveTransform(src,dst)
        warp = cv2.warpPerspective(res2,retval,(450,450))
        output[ri*50:(ri+1)*50-1 , ci*50:(ci+1)*50-1] = warp[ri*50:(ri+1)*50-1 , ci*50:(ci+1)*50-1].copy()

I'm just learning both OpenCV and C++, and I know this is probably trivial so I hope someone can spare some time and provide somewhat basic answer.

EDIT

As per request, here's the code. I've dealt with the first part, still unsure if this is the right way to go.

#pragma mark Correcting the defects
findContours(res, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
vector<cv::Point> centroids;
centroids.reserve(100);

for (int i = 0; i < contours.size(); i++) {
    vector<cv::Point> contour = contours.at(i);
    Moments mom = moments(contour);
    cv::Point center = cv::Point(int(mom.m10 / mom.m00), int(mom.m01 / mom.m00));
    centroids.push_back(center);
}

std::reverse(centroids.begin(), centroids.end());

struct {
    bool operator()(const cv::Point p1, const cv::Point p2) {
        return p1.x < p2.x;
    }
} pointXGreater;

for (int i = 0; i < 10; i++) {
    std::sort(centroids.begin() + i * 10, centroids.begin() + (i + 1) * 10, pointXGreater);
}

Mat b(centroids);
Mat bm = b.reshape(10, 10);

After drawing the centroids on the image with their indices, it seems that they are correct.

Now I'm stuck on the last part trying to decipher Python code not really knowing what it does. So far I got this:

Mat output = Mat::zeros(450, 450, CV_8U);

for (int i = 0; i < centroids.size(); i++) {
    cv::Point j = centroids.at(i);

    int ri = i / 10;
    int ci = i % 10;

    if (ci != 9 && ri != 9) {
        Mat src = ??
        Mat dst = ??
        Mat retval = getPerspectiveTransform(src, dst);
        Mat warp;
        warpPerspective(res2, warp, retval, (450, 450));
        Mat output = ??
    }
}

I'll keep on trying to make sense of it, but some help would really be appreciated since this kind of Python syntax isn't very friendly especially if you don't really know what's being done.

Community
  • 1
  • 1
Ilija
  • 151
  • 11
  • Why don't you post the C++ you've attempted for this particular section? Stack Overflow isn't a code-translation service, but we're happy to help if you have specific problems. Also, you might want to read up on [`std::sort()`](http://en.cppreference.com/w/cpp/algorithm/sort) if you haven't already. – Aurelius Aug 30 '13 at 22:41
  • I didn't post it because I didn't want to make the post even longer (I thought this is long as it is already). I know very well that SO isn't code-translation service, and I didn't expect it to be. I just thought this is quite specific subject and someone with enough experience could point me in the right direction. If it's still relevant tomorrow I'll expand my post with code I have tried. Also, I've checked std::sort out, and tried using it in one of my tries, but as I said I'm new to C++ and probably made some mistakes. – Ilija Aug 30 '13 at 22:52

1 Answers1

1

After a while of head banging, this is what I came up with (seems to work)

#pragma mark Correcting the defects
findContours(res, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
vector<cv::Point> centroids;
centroids.reserve(100);

for (int i = 0; i < contours.size(); i++) {
    vector<cv::Point> contour = contours.at(i);
    Moments mom = moments(contour);
    cv::Point center = cv::Point(int(mom.m10 / mom.m00), int(mom.m01 / mom.m00));
    centroids.push_back(center);
}

std::reverse(centroids.begin(), centroids.end());

struct {
    bool operator()(const cv::Point p1, const cv::Point p2) {
        return p1.x < p2.x;
    }
} pointXGreater;

for (int i = 0; i < 10; i++) {
    std::sort(centroids.begin() + i * 10, centroids.begin() + (i + 1) * 10, pointXGreater);
}

Mat bm = Mat(centroids);
bm = bm.reshape(2, 10);

Mat output(450, 450, CV_8UC3, CV_RGB(1, 1, 1));

for (int i = 0; i < centroids.size(); i++) {
    int ri = i / 10;
    int ci = i % 10;

    if (ci != 9 && ri != 9) {
        cv::Point2f src[4];
        src[0] = cv::Point2f(bm.at<cv::Point>(ri, ci).x, bm.at<cv::Point>(ri, ci).y);
        src[1] = cv::Point2f(bm.at<cv::Point>(ri, ci + 1).x, bm.at<cv::Point>(ri, ci + 1).y);
        src[2] = cv::Point2f(bm.at<cv::Point>(ri + 1, ci).x, bm.at<cv::Point>(ri + 1, ci).y);
        src[3] = cv::Point2f(bm.at<cv::Point>(ri + 1, ci + 1).x, bm.at<cv::Point>(ri + 1, ci + 1).y);

        cv::Point2f dst[4];
        dst[0] = cv::Point2f(ci * 50, ri * 50);
        dst[1] = cv::Point2f((ci + 1) * 50 - 1, ri * 50);
        dst[2] = cv::Point2f(ci * 50, (ri + 1) * 50 - 1);
        dst[3] = cv::Point2f((ci + 1) * 50 - 1, (ri + 1) * 50 - 1);

        Mat retval = getPerspectiveTransform(src, dst);
        Mat warp;
        warpPerspective(res2, warp, retval, cv::Size(450, 450));

        for (int j = ri * 50; j < (ri + 1) * 50 - 1; j++) {
            for (int k = ci * 50; k < (ci + 1) * 50 - 1; k++) {
                output.at<Vec3b>(j, k) = warp.at<Vec3b>(j, k);
            }
        }
    }
}
Ilija
  • 151
  • 11