OpenCv 2.3 C - 如何隔离图像内的对象

Posted

技术标签:

【中文标题】OpenCv 2.3 C - 如何隔离图像内的对象【英文标题】:OpenCv 2.3 C - How to isolate object inside image 【发布时间】:2012-05-06 03:08:38 【问题描述】:

我有一个像这样的图像:

我想删除数字周围的黑色行和列。 所以我希望结果是:

我试试这个:

void findX(IplImage* imgSrc,int* min, int* max)
    int i;
    int minFound=0;
    CvMat data;
    CvScalar maxVal=cvRealScalar(imgSrc->width * 255);
    CvScalar val=cvRealScalar(0);
    //For each col sum, if sum < width*255 then we find the min
    //then continue to end to search the max, if sum< width*255 then is new max
    for (i=0; i< imgSrc->width; i++)
        cvGetCol(imgSrc, &data, i);
        val= cvSum(&data);
        if(val.val[0] < maxVal.val[0])
            *max= i;
            if(!minFound)
                *min= i;
                minFound= 1;
            
        
    


void findY(IplImage* imgSrc,int* min, int* max)
    int i;
    int minFound=0;
    CvMat data;
    CvScalar maxVal=cvRealScalar(imgSrc->width * 255);
    CvScalar val=cvRealScalar(0);
    //For each col sum, if sum < width*255 then we find the min
    //then continue to end to search the max, if sum< width*255 then is new max
    for (i=0; i< imgSrc->height; i++)
        cvGetRow(imgSrc, &data, i);
        val= cvSum(&data);
        if(val.val[0] < maxVal.val[0])
            *max=i;
            if(!minFound)
                *min= i;
                minFound= 1;
            
        
    

CvRect findBB(IplImage* imgSrc)
    CvRect aux;
    int xmin, xmax, ymin, ymax;
    xmin=xmax=ymin=ymax=0;

    findX(imgSrc, &xmin, &xmax);
    findY(imgSrc, &ymin, &ymax);

    aux=cvRect(xmin, ymin, xmax-xmin, ymax-ymin);

    //printf("BB: %d,%d - %d,%d\n", aux.x, aux.y, aux.width, aux.height);

    return aux;


所以我使用:

IplImage *my_image = cvLoad....
CvRect bb = findBB(my_image);
IplImage *new_image = cvCreateImage(cvSize(bb.width,bb.height), my_image->depth, 1);
cvShowImage("test",new_image);

效果不好,因为我尝试检查新图像中是否有黑色行或列并且它们存在。我能做些什么?有人能帮我吗? (对不起我的英语!)

【问题讨论】:

你的图片只有一个数字,所以我不确定你所说的黑色行和列“四舍五入”数字是什么意思。 对不起我的英语了。对于“圆形”,我的意思是数字附近的所有值都是黑色 (0) 的行和列 嗯.. 我认为您在谈论像素级别。现在这样想,如果你反转这个图像,所有黑色的都会变成白色,而数字本身也会变成黑色。这不是更好吗? 我认为我没有很好地解释我的问题。我唯一想做的就是创建一个新图像,里面只有数字,所以从源图像中删除不包含数字的行和列,所以白色像素 如果您在 MS Paint 或其他绘图工具中修改您的输入图像以向我们展示您正在寻找的结果会更清晰。 【参考方案1】:

一种方法是简单地执行the bounding box technique 来检测数字,如下图所示:

由于您的图像已经过处理,我使用的边界框技术要简单得多。

在此过程之后,您真正需要做的就是将原始图像的 ROI(感兴趣区域)设置为框定义的区域,以实现 crop 效果并隔离对象:

请注意,在生成的图像中,边框中有一个额外的非白色像素行/列。好吧,它们也不是黑色的。那是因为我没有执行任何阈值方法将图像二值化为黑白。下面的代码演示了在图像的灰度版本上执行的边界框技术。

这几乎是实现您想要的目标的路线图。出于教育目的,我将分享我使用 OpenCV 的 C++ 接口编写的代码。我相信你有能力将它转换成 C 接口。

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

#include <vector>


int main(int argc, char* argv[])

    cv::Mat img = cv::imread(argv[1]);

    // Convert RGB Mat to GRAY
    cv::Mat gray;
    cv::cvtColor(img, gray, CV_BGR2GRAY);

    // Store the set of points in the image before assembling the bounding box
    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());
    

    // Compute minimal bounding box
    cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));

// Draw bounding box in the original image (debug 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("box", img);
//cv::imwrite("box.png", img);

    // Set Region of Interest to the area defined by the box
    cv::Rect roi;
    roi.x = box.center.x - (box.size.width / 2);
    roi.y = box.center.y - (box.size.height / 2);
    roi.width = box.size.width;
    roi.height = box.size.height;

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

    cv::imwrite("cropped.png", crop);
    cvWaitKey(0);

    return 0;

【讨论】:

如何转换 std::vector<:point> 点; cv::Mat_::iterator it = gray.begin(); cv::Mat_::iterator end = gray.end(); for (; it != end; ++it) if (*it) points.push_back(it.pos()); // 计算最小边界框 cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));进入c界面? 你开始劫持你自己的线程。请记住,我不是 OpenCV 的圣经。让我们每个线程保留一个问题,好吗?如果您有更多问题,请随时在新线程中提问。这次我会给你一个提示:检查cvCountNonZero() 有趣!我一直为此使用轮廓。这种技术要好得多,因为您不必决定要采用哪个轮廓。 @QadirHussain 哈哈不是机会,但感谢您的提问。 如果 box.angle 为 -90,则交换框的宽度和高度,从而导致 img(roi) 中的断言

以上是关于OpenCv 2.3 C - 如何隔离图像内的对象的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenCV 2.3 中为 Mat 数组赋值的问题 - 看起来很简单

opencv如何读取多边形区域内的像素值?

你如何摆脱在opencv c ++中裁剪图像后留下的空白?

如何从 PIL 图像创建 OpenCV 图像?

使用OpenCV检测损坏的形状

opencv4图像分割那些你不知道的API 代码可直接移植使用