【问题标题】:Drawing a boundary around some dots in an image在图像中的某些点周围绘制边界
【发布时间】:2015-06-05 00:33:48
【问题描述】:

我最近开始研究 opencv。我有一个图像在一行中有几个点。我想在这些点周围做一个矩形边框。 我已经应用了一些基本的 C 算法,但它对我不起作用。 这是我的代码。

int main()

{

    cv::Mat image = imread("C:/Users/Ravi Sharma/Desktop/img.bmp");

     for(int i =0; i < image.rows; i++){
        for(int k = 0; k <image.cols; k ++){
            if((image.at<cv::Vec3b>(k,i)[0] == 0)&&(image.at<cv::Vec3b>(k,i)[1] == 135)&&(image.at<cv::Vec3b>(k,i)[2] == 255))
            {
            (image.at<cv::Vec3b>(k,i)[0] = 0)&&(image.at<cv::Vec3b>(k,i)[1] = 0)&&(image.at<cv::Vec3b>(k,i)[2] = 255);
            }
        }

    }
    imwrite("C:/Users/Ravi Sharma/Desktop/img1.bmp",image);
    cv::namedWindow("Window1");
    cv::imshow("Window1",image);
    cv::waitKey(50000);
    return 1;
} 

此代码不更新像素值。请帮助我更正代码以获得所需的结果。 我如何使用 cvminmaxloc 函数来做同样的事情。 提前谢谢。

【问题讨论】:

  • 函数cvminmaxloc 查找最小和最大元素值及其位置。因此,如果我正确理解您的问题,那么此功能将无济于事。
  • 您可以使用 cvminmaxloc 查找单通道数组中最小/最大元素的位置。如果您反复调用它并比较/更新/存储 min 元素的最高/最低点(左上角、右下角),您可以使用它们绘制一个矩形。您将需要使用灰度图像,并且必须在每次调用后更新您的图像,以防止返回相同的位置(用白色填充最小位置)。
  • 你能举个例子解释一下吗? @user3510227
  • 如果轴对齐使用docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/…如果旋转矩形有类似的功能

标签: c++ image opencv image-processing


【解决方案1】:

我假设您的图像可以被视为二进制掩码,并且我们只对具有非零值的像素感兴趣。

要找到左上图中点周围的边界框,请遍历图像中的所有像素。对于每个非零像素,检查其xy-location 是否位于当前边界框之外。如果是,则更新您的边界框。生成的边界框将包围所有点,如上右图所示。

下面是一个最小工作示例,它生成包含随机采样点的图像,并为其确定边界框。

// This example uses OpenCV 3.0.0-beta. To use with OpenCV 2.4.* a
// few changes have to be made.

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

cv::Mat randomPoints( cv::Size size = cv::Size( 320, 240 ), int pointCount = 25 )
{
    cv::RNG rng( cv::getCPUTickCount() );
    cv::Mat image = cv::Mat3b::zeros( size );
    int radius = 3;
    cv::Scalar color( 0, 153, 255 );
    int thickness = -1;
    int margin = std::min( size.height, size.width ) / 4;

    for ( int i = 0; i < pointCount; ++i )
    {
        cv::Point p;
        p.x = rng.uniform( margin, size.width  - margin - 1 );
        p.y = rng.uniform( margin, size.height - margin - 1 );
        cv::circle( image, p, radius, color, thickness );
    }

    return image;
}

int main( int argc, char ** argv )
{
#if 0
    cv::Mat image = imread( "C:/Users/Ravi Sharma/Desktop/img.bmp" );
#else
    cv::Mat image = randomPoints();
#endif

    cv::Mat imageGray;
    cv::cvtColor( image, imageGray, cv::COLOR_BGR2GRAY );
    cv::Size size = imageGray.size();

    // The bounding box is defined by its top-left (TL) and bottom-right (BR)
    // coordinates.
    cv::Point tl( size.width, size.height );
    cv::Point br(          0,           0 );
    bool hasPoints = false;

    for ( int y = 0; y < size.height; ++y )
    {
        for ( int x = 0; x < size.width; ++x )
        {
            if ( imageGray.at<unsigned char>( y, x ) > 0 )
            {
                hasPoints = true;

                // Update the top-left corner.
                if ( x < tl.x ) tl.x = x;
                if ( y < tl.y ) tl.y = y;

                // Update the bottom-right corner.
                if ( x > br.x ) br.x = x;
                if ( y > br.y ) br.y = y;
            }
        }
    }

    // If the image contains any non-zero pixels, then draw the bounding box.
    if ( hasPoints )
        cv::rectangle( image, tl, br, cv::Scalar( 255, 255, 255, 255 ) );

    cv::namedWindow( "bounding-box" );
    cv::imshow( "bounding-box", image );
    cv::waitKey( 0 );

    cv::imwrite( "bounding-box.png", image );
}

编辑 1:

我也喜欢上面@Micka 提出的想法,即使用cv::boundingRect()。因此,在上述代码示例的循环中,您会将所有非零像素的xy 位置推入std::vector&lt; cv::Point &gt;,然后调用cv::boundingRect。在这种情况下,查看二维点云的convex hull 也很有趣。

【讨论】:

    【解决方案2】:

    这是一个专门使用 cvminmaxloc 的快速示例,我的 Python 不是很好,但我这里没有 C++ 的 OpenCV 设置,希望它应该可以理解。

    起始图片:

    结果图片:

    import cv2
    import copy
    import numpy
    
    #Read in image
    img = cv2.imread("Line.png")
    
    #Top Left Point
    y1,x1 = img.shape[:2]
    
    #Bottom right point
    y2,x2 = 0, 0
    
    #Values returned from minmaxloc
    min_val, max_val, min_loc, max_loc = 0,0,(0,0),(0,0)
    
    #create grayscale copy of our img to work with
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    #Get values
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray_img)
    
    #White = 255 #Black = 0
    while(min_val != 255):
    
            #Check points and update if needed
            if(min_loc[0] < x1):
                    x1 = min_loc[0]
            if(min_loc[1] < y1):
                    y1 = min_loc[1]
            if(min_loc[0] > x2):
                    x2 = min_loc[0]
            if(min_loc[1] > y2):
                    y2 = min_loc[1]
    
            #Update image - remove current result
            gray_img[min_loc[1], min_loc[0]] = 255
    
            #Get next values
            min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray_img)
    
    #Done checking - draw rectangle over reference + display
    cv2.rectangle(img, (x1,y1), (x2, y2), (0,255,0), 1)
    
    #Display
    cv2.namedWindow('image')
    cv2.imshow('image', img)
    cv2.waitKey(0)
    
    #Clear up windows
    cv2.destroyAllWindows()
    
    #Write result
    cv2.imwrite('result.png',img)
    

    【讨论】:

    • 感谢大家的帮助!我已经写了一个代码。它正在制作一个矩形,但没有覆盖该点。它从 (0,0) 开始,直到找到第一个亮像素。我希望它在点周围形成边界。我的代码是:
    • 检查您的初始点值,左上角应设置为图像的宽度和高度,以便任何找到的像素坐标覆盖它。
    猜你喜欢
    • 1970-01-01
    • 2021-12-03
    • 2016-08-02
    • 2015-02-13
    • 1970-01-01
    • 2016-11-20
    • 2020-08-04
    • 2013-02-20
    • 1970-01-01
    相关资源
    最近更新 更多