将图像裁剪成碎片然后加入,这可能使用 OpenCV 吗?

Posted

技术标签:

【中文标题】将图像裁剪成碎片然后加入,这可能使用 OpenCV 吗?【英文标题】:Crop image into pieces and then join, is that possible using OpenCV? 【发布时间】:2013-11-29 03:36:53 【问题描述】:

我有几个来自彩色图像的样本,我应该将它们转换为二进制。我通过使用自适应阈值获得了最好的结果。

这些数字非常好,定义明确,但周围很嘈杂,例如,分隔每个数字的这些“垂直线”最终被读取为用于 OCR 工具的数字 1。

然后我注意到图像周围的数字很干净。我想我是否可以只剪掉数字(在将图片制作成黑白之前或之后?),然后将这些数字“粘贴”到白色背景上。

我尝试应用 erosiondilation,但仍有许多剩余的“点”。如果我能按照我的想法做(上图),它会减少侵蚀/扩张并增加切割前数字周围的“清洁”,我不知道。

这可能吗?我说的有道理吗?如果是,我怎么能使用 OpenCV 做到这一点?有什么建议吗?

我正在使用的一些图片:

注意:以上图片没有经过腐蚀和/或膨胀的过程,只是自适应阈值处理。


更新:

@Mahm00d,我用第一张图试了你说的,得到了​​下图,非常好,但是前两个数字的反射问题仍然存在。有没有什么办法解决这一问题?我应用了自适应阈值,但图像仍然很噪点。

GaussianBlur + 带有 OTSU 标志的阈值:

GaussianBlur + 自适应阈值:

【问题讨论】:

查看我的更新答案。 【参考方案1】:

通常最好先使用一些去噪技术,例如高斯/中值模糊,然后再进行阈值处理和形态:

(Java 代码)

Imgproc.cvtColor(inputMat, gMat, Imgproc.COLOR_RGB2GRAY);
// Gaussian blur : 21x21 window, sigma = 50.0 (select these accordignly)
Imgproc.GaussianBlur(gMat, gMat, new Size(21.0, 21.0), 50.0);
// Otsu thresholding (or any other thresholding techinique...)
Imgproc.threshold(gMat, gMat, 0, 255, Imgproc.THRESH_OTSU | Imgproc.THRESH_BINARY);

你的输出:

以上代码输出:


更新:

这些问题通常需要对参数值进行一些调整才能获得良好的结果并达到最佳值。在第二张图片的情况下,这是我使用的代码(自适应阈值)以获得更好的结果:

Imgproc.GaussianBlur(inImg, inImg, new Size(21.0, 21.0), 50.0);
Imgproc.adaptiveThreshold(inImg, inImg, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 111, -20);

结果:

当然它并不完美,但至少反射被移除了。此外,形态学过程可以帮助产生更好的结果。

【讨论】:

【参考方案2】:

一种解决方案是应用膨胀和腐蚀,找到所有小于 X 像素的轮廓并用白色填充它们:

int main()

    // Load the image as a Grayscale
    Mat image = imread("image.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    // Threshold the image
    image = image > 120;
    // Create bigger image with image width and height + 10 pixels
    Mat image_big = Mat::zeros( image.size().height + 10, image.size().width + 10, CV_8UC1 );
    // Set bigger image to be all white
    image_big.setTo(255);

    Mat image_big_copy;

    // This may vary, you must find it for yourself
    // Dilate image 4 times and erode once
    dilate(image, image, Mat(), Point(-1,-1), 4);
    erode(image, image, Mat(), Point(-1,-1));

    // Copy image in the center of bigger image so you left 5px around image blank/white
    // Create a new ROI that points to center of the bigger image
    Mat image_big_roi = image_big( Rect(Point(5, 5), Size(image.size())) );
    // Copy image to the bigger image ROI
    addWeighted(image_big_roi, 0., image, 1., 0., image_big_roi);

    // Create a data copy of image_big
    image_big.copyTo(image_big_copy);

    // Find all contours in a given image and store them in contours
    vector<vector<Point> > contours;
    findContours(image_big_copy, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

    for( int i = 0; i < contours.size(); i++ )
    
        // This is your condition to filter out unwanted contours etc.
        // For every contour if its area is bigger/smaller than the sum of pixels
        if ( fabs(contourArea(Mat(contours[i]))) < 800 )
        
            // Fill a contour with white color
            drawContours(image_big, contours, i, Scalar(255), CV_FILLED);
        
    

    imshow("Image original", image);
    imshow("Image edited", image_big);
    waitKey(0);

    return 0;

原图:

之后:

【讨论】:

以上是关于将图像裁剪成碎片然后加入,这可能使用 OpenCV 吗?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV跟踪轮廓将整个图像跟踪为最大轮廓?

Opencv和python用于自动裁剪

如何使用 OpenCV 裁剪图像中的白色斑块并制作护照大小的照片

如何从网络摄像头 OpenCV 裁剪圆形图像并删除背景

OpenCV用椭圆裁剪图像

opencv图像裁剪与拼接