user3839833
user3839833

Reputation: 131

Find 4 specific corner pixels and use them with warp perspective

I'm playing around with OpenCV and I want to know how you would build a simple version of a perspective transform program. I have a image of a parallelogram and each corner of it consists of a pixel with a specific color, which is nowhere else in the image. I want to iterate through all pixels and find these 4 pixels. Then I want to use them as corner points in a new image in order to warp the perspective of the original image. In the end I should have a zoomed on square.

Point2f src[4]; //Is this the right datatype to use here?
int lineNumber=0;
//iterating through the pixels
for(int y = 0; y < image.rows; y++)
{
    for(int x = 0; x < image.cols; x++)
    {
        Vec3b colour = image.at<Vec3b>(Point(x, y));
    if(color.val[1]==245 && color.val[2]==111 && color.val[0]==10) { 
        src[lineNumber]=this pixel // something like Point2f(x,y) I guess
        lineNumber++;
    }
    }
}
/* I also need to get the dst points for getPerspectiveTransform 
and afterwards warpPerspective, how do I get those? Take the other 
points, check the biggest distance somehow and use it as the maxlength to calculate 
the rest? */

How should you use OpenCV in order to solve the problem? (I just guess I'm not doing it the "normal and clever way") Also how do I do the next step, which would be using more than one pixel as a "marker" and calculate the average point in the middle of multiple points. Is there something more efficient than running through each pixel?

Something like this basically:

enter image description here

Upvotes: 4

Views: 2549

Answers (1)

Miki
Miki

Reputation: 41765

Starting from an image with colored circles as markers, like:

enter image description here

Note that is a png image, i.e. with a loss-less compression which preserves the actual color. If you use a lossy compression like jpeg the colors will change a little, and you cannot segment them with an exact match, as done here.

You need to find the center of each marker.

  1. Segment the (known) color, using inRange
  2. Find all connected components with the given color, with findContours
  3. Find the largest blob, here done with max_element with a lambda function, and distance. You can use a for loop for this.
  4. Find the center of mass of the largest blob, here done with moments. You can use a loop also here, eventually.
  5. Add the center to your source vertices.

Your destination vertices are just the four corners of the destination image.

You can then use getPerspectiveTransform and warpPerspective to find and apply the warping.

The resulting image is:

enter image description here

Code:

#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;

int main()
{
    // Load image
    Mat3b img = imread("path_to_image");

    // Create a black output image
    Mat3b out(300,300,Vec3b(0,0,0));

    // The color of your markers, in order
    vector<Scalar> colors{ Scalar(0, 0, 255), Scalar(0, 255, 0), Scalar(255, 0, 0), Scalar(0, 255, 255) }; // red, green, blue, yellow

    vector<Point2f> src_vertices(colors.size());
    vector<Point2f> dst_vertices = { Point2f(0, 0), Point2f(0, out.rows - 1), Point2f(out.cols - 1, out.rows - 1), Point2f(out.cols - 1, 0) };

    for (int idx_color = 0; idx_color < colors.size(); ++idx_color)
    {
        // Detect color
        Mat1b mask;
        inRange(img, colors[idx_color], colors[idx_color], mask);

        // Find connected components
        vector<vector<Point>> contours;
        findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

        // Find largest
        int idx_largest = distance(contours.begin(), max_element(contours.begin(), contours.end(), [](const vector<Point>& lhs, const vector<Point>& rhs) {
            return lhs.size() < rhs.size();
        }));

        // Find centroid of largest component
        Moments m = moments(contours[idx_largest]);
        Point2f center(m.m10 / m.m00, m.m01 / m.m00);

        // Found marker center, add to source vertices
        src_vertices[idx_color] = center;
    }

    // Find transformation
    Mat M = getPerspectiveTransform(src_vertices, dst_vertices);

    // Apply transformation
    warpPerspective(img, out, M, out.size());

    imshow("Image", img);
    imshow("Warped", out);
    waitKey();

    return 0;
}

Upvotes: 3

Related Questions