如何确定感兴趣的区域,然后使用OpenCV裁剪图像 [英] How to determine a region of interest and then crop an image using OpenCV

查看:159
本文介绍了如何确定感兴趣的区域,然后使用OpenCV裁剪图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问了一个类似的问题 操作。





之后, Mat 查找角落像素是微不足道的,我在回答。

  #include< cv.h> 
#include< highgui.h>

int main(int argc,char * argv [])
{
cv :: Mat img = cv :: imread(argv [1]);
std :: cout<< 原始图像大小:<< img.size()<<的std :: ENDL;

//将RGB Mat转换为GRAY
cv :: Mat grey;
cv :: cvtColor(img,grey,CV_BGR2GRAY);
std :: cout<< 灰色图像大小:<< gray.size()<<的std :: ENDL;

//侵蚀图像以消除不必要的噪音
int erosion_size = 5;
cv :: Mat element = cv :: getStructuringElement(cv :: MORPH_CROSS,
cv :: Size(2 * erosion_size + 1,2 * erosion_size + 1),
cv :: Point (erosion_size,erosion_size));
cv :: erode(灰色,灰色,元素);

//扫描图像搜索点并将它们存储在向量中
std :: vector< cv :: Point>点;
cv :: Mat_< uchar> :: iterator it = gray.begin< uchar>();
cv :: Mat_< uchar> :: iterator end = gray.end< uchar>();
for(; it!= end; it ++)
{
if(* it)
points.push_back(it.pos());
}

//从积分中算出ROI的大小
int left,right,top,bottom;
for(int i = 0; i< points.size(); i ++)
{
if(i == 0)//初始化角点值
{
left = right = points [i] .x;
top = bottom = points [i] .y;
}

if(points [i] .x< left)
left = points [i] .x;

if(points [i] .x> right)
right = points [i] .x;

if(points [i] .y< top)
top = points [i] .y;

if(points [i] .y> bottom)
bottom = points [i] .y;
}
std :: vector< cv :: Point> box_points;
box_points.push_back(cv :: Point(left,top));
box_points.push_back(cv :: Point(left,bottom));
box_points.push_back(cv :: Point(right,bottom));
box_points.push_back(cv :: Point(right,top));

//为ROI计算最小边界框
//注意:由于某些未知原因,框的宽度/高度会被切换。
cv :: RotatedRect box = cv :: minAreaRect(cv :: Mat(box_points));
std :: cout<< box w:<< box.size.width<< h:<< box.size.height<<的std :: ENDL;

//在原始图像中绘制边界框(调试目的)
// cv :: Point2f vertices [4];
//box.points(vertices);
// for(int i = 0; i< 4; ++ i)
// {
// cv :: line(img,vertices [i],vertices [( i + 1)%4],cv :: Scalar(0,255,0),1,CV_AA);
//}
// cv :: imshow(Original,img);
// cv :: waitKey(0);

//将ROI设置为框$ $ $ b //所定义的区域注意:因为框的宽度/高度被切换,
//它们是手动切换的代码如下:
cv :: Rect roi;
roi.x = box.center.x - (box.size.height / 2);
roi.y = box.center.y - (box.size.width / 2);
roi.width = box.size.height;
roi.height = box.size.width;
std :: cout<< roi @<< roi.x<< ,<< roi.y<< << roi.width<< x<< roi.height<<的std :: ENDL;

//将原始图像裁剪为定义的ROI
cv :: Mat crop = img(roi);

//显示裁剪的投资回报率
cv :: imshow(裁剪投资回报率,作物);
cv :: waitKey(0);

返回0;
}


I asked a similar question here but that is focused more on tesseract.

I have a sample image as below. I would like to make the white square my Region of Interest and then crop out that part (square) and create a new image with it. I will be working with different images so the square won't always be at the same location in all images. So I will need to somehow detect the edges of the square.

What are some pre-processing methods I can perform to achieve the result?

解决方案

Using your test image I was able to remove all the noises with a simple erosion operation.

After that, a simple iteration on the Mat to find for the corner pixels is trivial, and I talked about that on this answer. For testing purposes we can draw green lines between those points to display the area we are interested at in the original image:

At the end, I set the ROI in the original image and crop out that part.

The final result is displayed on the image below:

I wrote a sample code that performs this task using the C++ interface of OpenCV. I'm confident in your skills to translate this code to Python. If you can't do it, forget the code and stick with the roadmap I shared on this answer.

#include <cv.h>
#include <highgui.h>

int main(int argc, char* argv[])
{
    cv::Mat img = cv::imread(argv[1]);
    std::cout << "Original image size: " << img.size() << std::endl;

    // Convert RGB Mat to GRAY
    cv::Mat gray;
    cv::cvtColor(img, gray, CV_BGR2GRAY);
    std::cout << "Gray image size: " << gray.size() << std::endl;

    // Erode image to remove unwanted noises
    int erosion_size = 5;
    cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS,
                                       cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
                                       cv::Point(erosion_size, erosion_size) );
    cv::erode(gray, gray, element);

    // Scan the image searching for points and store them in a vector
    std::vector<cv::Point> points;
    cv::Mat_<uchar>::iterator it = gray.begin<uchar>();
    cv::Mat_<uchar>::iterator end = gray.end<uchar>();
    for (; it != end; it++)
    {
        if (*it) 
            points.push_back(it.pos()); 
    }

    // From the points, figure out the size of the ROI
    int left, right, top, bottom;
    for (int i = 0; i < points.size(); i++)
    {
        if (i == 0) // initialize corner values
        {
            left = right = points[i].x;
            top = bottom = points[i].y;
        }

        if (points[i].x < left)
            left = points[i].x;

        if (points[i].x > right)
            right = points[i].x;

        if (points[i].y < top)
            top = points[i].y;

        if (points[i].y > bottom)
            bottom = points[i].y;
    }
    std::vector<cv::Point> box_points;
    box_points.push_back(cv::Point(left, top));
    box_points.push_back(cv::Point(left, bottom));
    box_points.push_back(cv::Point(right, bottom));
    box_points.push_back(cv::Point(right, top));

    // Compute minimal bounding box for the ROI
    // Note: for some unknown reason, width/height of the box are switched.
    cv::RotatedRect box = cv::minAreaRect(cv::Mat(box_points));
    std::cout << "box w:" << box.size.width << " h:" << box.size.height << std::endl;

    // Draw bounding box in the original image (debugging purposes)
    //cv::Point2f vertices[4];
    //box.points(vertices);
    //for (int i = 0; i < 4; ++i)
    //{
    //    cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
    //}
    //cv::imshow("Original", img);
    //cv::waitKey(0);

    // Set the ROI to the area defined by the box
    // Note: because the width/height of the box are switched, 
    // they were switched manually in the code below:
    cv::Rect roi;
    roi.x = box.center.x - (box.size.height / 2);
    roi.y = box.center.y - (box.size.width / 2);
    roi.width = box.size.height;
    roi.height = box.size.width;
    std::cout << "roi @ " << roi.x << "," << roi.y << " " << roi.width << "x" << roi.height << std::endl;

    // Crop the original image to the defined ROI
    cv::Mat crop = img(roi);

    // Display cropped ROI
    cv::imshow("Cropped ROI", crop);
    cv::waitKey(0);

    return 0;
}

这篇关于如何确定感兴趣的区域,然后使用OpenCV裁剪图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆