Crop Triangle with opencv c++

2019-06-28 09:10发布

问题:

User,

I want to crop that Triangle on the image and show it in another window with opencv c++. I know all three Coordinates. Can anyone help me? I did not find any answer on the Internet about "triangle cropping". Thanks!

EDIT: The Problem here is that i cannot use ROI for cropping the Triangle. I have to copy just the triangle without any background or something around. Is it possible to create my own ROI by knowing the Coordinates of the triangle [p1(302,179), p2(329,178), p3(315,205)]?

回答1:

cv::Mat inputImage = cv::imread("input.png");
if (inputImage.channels() > 1)
{
    cv::cvtColor(inputImage, inputImage, CV_RGB2GRAY);
}

// replace these values with your actual coordinates
// I found these by first saving your provided image, then 
// using Microsoft Paint
int x0 = 242;
int y0 = 164;
int x1 = 314;
int y1 = 38;
int x2 = 387;
int y2 = 164;

// then create a line masking using these three points
cv::Mat lineMask = cv::Mat::zeros(inputImage.size(), inputImage.type());
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x1, y1), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);

// perform contour detection on your line mask
cv::vector<cv::vector<cv::Point>> contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(lineMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

// calculate the distance to the contour
cv::Mat raw_dist(lineMask.size(), CV_32FC1);

for (int i = 0; i < lineMask.rows; i++)
{
    for (int j = 0; j < lineMask.cols; j++)
    {
        raw_dist.at<float>(i, j) = cv::pointPolygonTest(contours[0], cv::Point2f(j, i), true);
    }
}

double minVal; double maxVal;
cv::minMaxLoc(raw_dist, &minVal, &maxVal, 0, 0, cv::Mat());
minVal = std::abs(minVal);
maxVal = std::abs(maxVal);

// depicting the distances graphically
cv::Mat mask = cv::Mat::zeros(inputImage.size(), CV_8UC1);

for (int i = 0; i < mask.rows; i++)
{
    for (int j = 0; j < mask.cols; j++)
    {
        if (raw_dist.at<float>(i, j) < 0)
        {
            mask.at<uchar>(i, j) = static_cast<uchar>(0);
            continue;
        }           
        mask.at<uchar>(i, j) = static_cast<uchar>(255);
    }
}

// inverse the input image
cv::Mat invInput;   
cv::bitwise_not(inputImage, invInput);

// then get only the region of your triangle
cv::Mat outputImage;
invInput.copyTo(outputImage, mask);
cv::bitwise_not(outputImage, outputImage);

// display for debugging purpose
cv::imshow("inputImage", inputImage);
cv::imshow("lineMask", lineMask);
cv::imshow("mask", mask);
cv::imshow("outputImage", outputImage);
cv::waitKey();  

This is your inputImage:

This is your lineMask:

This is your created binary mask:

And this is your final outputImage:

References:

OpenCV draw line

OpenCV findContours

Point Polygon Test



回答2:

you can do it by using mask as shown with the code below

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main( int, char** argv )
{
    Mat src = imread( argv[1] );
    Mat gray;

    cvtColor(src, gray, COLOR_BGR2GRAY );
    gray = gray < 127;

    vector<vector<Point> > contours;

    findContours(gray, contours,
                 RETR_EXTERNAL,
                 CHAIN_APPROX_SIMPLE);

    for( size_t i = 0; i< contours.size(); i++ )
    {
        Rect rect = boundingRect(contours[i]);
        Mat mask = gray(rect);
        Mat srcROI = src(rect);
        srcROI.setTo(Scalar(0,0,255),mask);
        imshow("srcROI",srcROI);
        waitKey();
    }

    imshow( "result", src );

    waitKey(0);
    return(0);
}

EDIT: according the change on the question i suggest the test code below

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;
using namespace std;

int main( int, char** argv )
{
    Mat src = imread("lena.jpg");
    vector<Point> points;
    points.push_back( Point(200,200));
    points.push_back( Point(370,370));
    points.push_back( Point(220,410));

    Mat mask = Mat::zeros( src.size(), CV_8UC1 );
    fillConvexPoly( mask, points, Scalar( 255 ));

    Rect rect = boundingRect( points );
    Mat roi = src( rect ).clone();
    mask = mask( rect ).clone();

    rect.x = rect.x - 180;
    rect.y = rect.y - 180;

    Mat srcROI = src( rect );
    roi.copyTo( srcROI, mask );

    imshow( "result", src );

    waitKey(0);
    return(0);
}



回答3:

  • As you told that you know co-ordinates of the triangle, using below code you can find triangle.

    Mat image = imread("imagePath");
    bitwise_not(image, image);
    Mat grayImage;
    cv::cvtColor(image, grayImage, CV_RGB2GRAY);
    cv::vector<cv::vector<cv::Point> > contours;
    cv::vector<cv::Vec4i> hierarchy;
    cv::findContours(grayImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
    Mat contourMat(grayImage.size(), grayImage.type(), Scalar(255));
    for(int i = 0; i < contours.size(); i++)
    {
        if(contours[i].data()->x == 314 && contours[i].data()->y == 37)
            drawContours(contourMat, contours, i, Scalar(0), CV_FILLED, 8, hierarchy);
    }
    imshow("WindowName", contourMat);
    
  • Hope this will help.