将图像裁剪成碎片然后加入,是否可以使用OpenCV?

时间:2013-11-29 03:36:54

标签: c++ opencv image-processing computer-vision edge-detection

我有几个彩色图像的样本,我应该变成二进制。我使用自适应阈值获得了最佳结果。

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

然后我注意到数字周围的图像很干净。我想如果我只能剪掉数字(在制作黑白图片之前或之后?)然后将这些数字“粘贴”为白色背景。

我尝试应用侵蚀扩张,但仍有许多剩余的“点”。如果我可以做我正在考虑的事情(上图),它会减少侵蚀/扩张并增加切割前数字周围的“清洁”,我不知道。

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

我正在使用的一些图片:

rgb image1

image1 after adaptive threshold

rgb image2

image2 after adaptive threshold

注意:上面的图片没有经过侵蚀和/或扩张过程,只有自适应阈值处理。


更新

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

GaussianBlur +带OTSU标志的阈值: gaussian + otsu

GaussianBlur +自适应阈值: gaussian + adaptive

2 个答案:

答案 0 :(得分:3)

在进行阈值处理和形态学处理之前,首先使用一些去噪技术,比如高斯/中值模糊通常会很好:

(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);

你的输出:

enter image description here

以上代码输出:

enter image description here


<强>更新

这些问题通常需要使用参数值来获得良好的结果并获得最佳值。在第二个图像的情况下,这是我使用的代码(自适应阈值)以获得更好的结果:

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);

结果:

enter image description here

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

答案 1 :(得分: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;
}

原始图片:

enter image description here

后:

enter image description here