从背景中检测纸张几乎与纸张颜色相同 [英] detect paper from background almost same as paper color

查看:95
本文介绍了从背景中检测纸张几乎与纸张颜色相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从图像中检测出一张纸。好吧,我从



这是供参考的代码

  im1 = imread('http:// www。 imageno.com/image.php?id=ai7b91pm9fcs&kk=1089743759'); 
im2 = imread(’http://www.imageno.com/image.php?id=k99c9xpd6phs&kk=3354581295’);

%转换为灰度
gim1 = rgb2gray(im1);
gim2 = rgb2gray(im2);

%获取图像的大小
[m1,n1] = size(gim1);
[m2,n2] = size(gim2);

%拍摄图像的梯度
[Gx1,Gy1] =梯度(double(gim1));
[Gx2,Gy2] =梯度(double(gim2));

取X和Y方向上的梯度量
Gxy1 = sqrt(Gx1。^ 2 + Gy1。^ 2);
Gxy2 = sqrt(Gx2。^ 2 + Gy2。^ 2);

%降采样图像(以减少噪声)
scale_factor = 100;
small1 = imresize(Gxy1,[m1 / scale_factor n1 / scale_factor]);
small2 = imresize(Gxy2,[m2 / scale_factor n2 / scale_factor]);

%升采样图像(至原始大小)
big1 = imresize(small1,[m1 n1]);
big2 = imresize(small2,[m2 n2]);

%转换为二进制掩码
bw1 =(big1> = 1);
bw2 =(big2> = 1);

%显示图像
图(1);
subplot(2,4,1); imshow(gim1); title('灰度1');
subplot(2,4,5); imshow(gim2); title('grayscale 2');

这些梯度有些欺骗。在matlab中,当看到图像
%of类型为 double时,它将其映射为0 =黑色和1 = white。任何> = 1都将
%限制为1
子图(2,4,2); imshow(Gxy1); title('gradient 1');
subplot(2,4,6); imshow(Gxy2); title(’gradient 2’);

子图(2,4,3); imshow(big1); title(’down-> up sampled 1’);
subplot(2,4,7); imshow(big2); title(’down-> up sampled 2’);

%这只是一些matlab巫术,因此我可以非常有效地将2D蒙版与
%3D图像(rgb)相乘
subplot(2,4,4 ); imshow(bsxfun(@ times,im1,uint8(bw1))); title('masked image 1');
subplot(2,4,8); imshow(bsxfun(@ times,im2,uint8(bw2))); title('masked image 2');


I am trying to detect a piece of paper from an image. Well I have had help from posts like this . But one difference is that my background color is almost same as the paper color, and I am getting wrong result.

[edit] By wrong result I mean the paper outline contour is not detected at all. instead the largest contour covers the whole image.

image1

image2

My code so far (using emgu cv and c#)

MemStorage storage = new MemStorage();
        List<Contour<Point>> candidateList = new List<Contour<Point>>();
        List<double> areaList = new List<double>();

        Image<Bgr, Byte> inputImage = new Image<Bgr, Byte>(image);
        //Rectangle roi = new Rectangle(15, 15, image.Width - 15, image.Height - 15);
        //inputImage.ROI = roi;
        //inputImage = inputImage.Copy();

        double threshHeight = inputImage.Size.Height * 0.50;
        double threshWidth = inputImage.Size.Width * 0.50;


        //std::vector<std::vector<cv::Point> > squares;
        //cv::Mat pyr, timg, gray0(_image.size(), CV_8U), gray;
        int thresh = 50, N = 5;
        //cv::pyrDown(_image, pyr, cv::Size(_image.cols/2, _image.rows/2));
        //cv::pyrUp(pyr, timg, _image.size());
        //std::vector<std::vector<cv::Point> > contours;

        Image<Gray, Byte> [] gray0 = new Image<Gray,byte>[3];


        for( int c = 0; c < 3; c++ ) {
            try{
                int [] ch = {c, 0};
                gray0[c] = new Image<Gray,byte>(inputImage.Size);
                CvInvoke.cvMixChannels(new IntPtr[] { inputImage }, 1, new IntPtr[]{gray0[c]}, 1, ch, 1);
                Image<Gray, Byte> gray = new Image<Gray,byte>(inputImage.Size);
                for (int l = 0 ; l < N ; l++){
                    if (l == 0){
                        Image<Gray, Byte> cannyImage = gray0[c].Canny(0, thresh, 5);
                        CvInvoke.cvDilate(cannyImage, gray, IntPtr.Zero, 1);
                        //CvInvoke.cvShowImage("ch " + c + "-" + l, gray);
                    }else{
                        CvInvoke.cvThreshold(gray0[c], gray, (l + 1)*255/N, 255, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY);
                        //CvInvoke.cvShowImage("ch " + c + "-" + l, gray0[c]);
                    }

                    //CvInvoke.cvShowImage("image", gray);    

                    for (Contour<Point> contours = gray.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST, storage); contours != null; contours = contours.HNext){
                        Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.02, storage);
                        if (currentContour.Count() >= 4){
                            if (currentContour.Area > 3000){
                            //if (currentContour.BoundingRectangle.Width >= threshWidth && currentContour.BoundingRectangle.Height > threshHeight){
                                candidateList.Add(currentContour);
                                areaList.Add(currentContour.Area);
                                inputImage.Draw(currentContour, new Bgr(255, 0, 0), 1);
                            }
                        }
                    }
                }




            }catch(Exception ex){
                Debug.WriteLine(ex.Message);
            }


        }

        /* finding the biggest one */
        double area = -1.0;
        Contour<Point> paper = null;
        for (int i = 0 ; i < candidateList.Count ; i++){
            if (areaList[i] > area){
                area = areaList[i];
                paper = candidateList[i];
            }
        }

        if (paper != null){
            if (paper.BoundingRectangle.Width >= threshWidth && paper.BoundingRectangle.Height > threshHeight){
                inputImage.Draw(paper, new Bgr(0, 0, 255), 2);

            }
        }
        return inputImage.ToBitmap();

Please let me know how to process these images.

解决方案

I did this in matlab (sorry I'm not really proficient at OpenCV) but you should be able to emulate the code. I tried to make it very simple. I noticed that the gradient of the original images really highlights where the paper is. So I used that to make a "rough" outline of the paper. Using the gradient is a good starting point, and maybe you can start from there. I just downsampled, then upsampled the image (emulating morphological operations to clean the image, since you lose all the small details).

You might get better results if you smooth the image out first (with a Gaussian filter maybe) I didn't try it, but maybe you can give it a try. Here is the result

And here is the code for reference

im1 = imread('http://www.imageno.com/image.php?id=ai7b91pm9fcs&kk=1089743759');
im2 = imread('http://www.imageno.com/image.php?id=k99c9xpd6phs&kk=3354581295');

%converts to grayscale
gim1 = rgb2gray(im1);
gim2 = rgb2gray(im2);

%gets size of images
[m1, n1] = size(gim1);
[m2, n2] = size(gim2);

%takes gradient of image
[Gx1, Gy1] = gradient(double(gim1));
[Gx2, Gy2] = gradient(double(gim2));

%takes magnitude of gradient in X and Y direction
Gxy1 = sqrt(Gx1.^2 + Gy1.^2);
Gxy2 = sqrt(Gx2.^2 + Gy2.^2);

%downsamples image (to reduce noise)
scale_factor = 100;
small1 = imresize(Gxy1, [m1/scale_factor n1/scale_factor]);
small2 = imresize(Gxy2, [m2/scale_factor n2/scale_factor]);

%upsamples image (to original size)
big1 = imresize(small1, [m1 n1]);
big2 = imresize(small2, [m2 n2]);

%converts to binary mask
bw1 = (big1 >= 1);
bw2 = (big2 >= 1);

%displays images
figure(1);
subplot(2,4,1);imshow(gim1);title('grayscale 1');
subplot(2,4,5);imshow(gim2);title('grayscale 2');

%these gradients are a little deceiving. In matlab when it sees an image 
%of type "double" its maps it so 0=black and 1=white. anything >=1 gets 
%clipped to 1
subplot(2,4,2);imshow(Gxy1);title('gradient 1');
subplot(2,4,6);imshow(Gxy2);title('gradient 2');

subplot(2,4,3);imshow(big1);title('down->up sampled 1');
subplot(2,4,7);imshow(big2);title('down->up sampled 2');

%this is just some matlab witchcraft so I can multiply the 2D mask with a
%3D image (r g b) in a very efficient manner
subplot(2,4,4);imshow(bsxfun(@times,im1,uint8(bw1)));title('masked image 1');
subplot(2,4,8);imshow(bsxfun(@times,im2,uint8(bw2)));title('masked image 2');

这篇关于从背景中检测纸张几乎与纸张颜色相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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