2013-01-08 110 views
6

我试图分割名片和背景颜色分割它们作为不同的感兴趣的区域对待它们。背景颜色图像分割 - OpenCV Android

例如这种卡: Sample business card

应该能够是被分成两个图像作为有2个的背景色。有没有关于如何解决这个问题的建议?我试过做一些轮廓分析,结果并不是太成功。

其他例如卡: enter image description here

这卡应该给3个分割,因为有三个部分,即使它的只有2种颜色(尽管2个色会好起来的)。

enter image description here

因为它只是一个背景色以上的卡应该举一个分割。

我还没有想过渐变背景。

回答

8

这取决于其他卡怎么看,但如果图像都是在伟大的品质,应该不会太难。

在您发布的例子,你可以只收集边界像素(最左边一列,最右边一栏,第一行,最后一行)的颜色,并把你找到尽可能的背景颜色。也许检查是否有足够的像素大致相同的颜色。你需要某种距离测量。一个简单的解决方案就是在RGB色彩空间中使用欧式距离。

一个更通用的解决办法是找到在整个图像的颜色直方图集群和(公差再次)对待每一个颜色具有比总像素量作为背景色的X%以上。但是你定义的背景取决于你想要达到什么以及你的图像的外观。

如果需要进一步的建议,您可以发布更多的图像和标签如何被检测为背景色你想要的图像部分,什么parst没有。

-

编辑:您的两张新图像也显示相同的图案。背景颜色占据了图像的很大一部分,没有噪音,也没有颜色渐变。因此,一个简单的方法可能如下所示:

如果不使用这种方法工作的例子,只是张贴。

+0

我已经添加了几个示例卡片。如果可能,你还可以将你的答案更多地与OpenCV联系起来吗? – SalGad

+0

我根据新的信息编辑了我的答案。 –

+0

谢谢@Dobi,我会试试这个,让你知道:) – SalGad

0

作为一种也可以用颜色渐变找到背景的方法,可以使用canny。下面的代码(是的,不是机器人,我知道,但结果应该是相同的,如果你移植它)适用于迄今为止发布的三个示例图像。如果您有其他图片,请不要使用此图片,请告诉我。

#include <opencv2/opencv.hpp> 

using namespace cv; 
using namespace std; 

Mat src; 
Mat src_gray; 
int canny_thresh = 100; 
int max_canny_thresh = 255; 
int size_per_mill = 120; 
int max_size_per_mill = 1000; 
RNG rng(12345); 

bool cmp_contour_area_less(const vector<Point>& lhs, const vector<Point>& rhs) 
{ 
    return contourArea(lhs) < contourArea(rhs); 
} 

void Segment() 
{ 
    Mat canny_output; 
    vector<vector<Point> > contours; 
    vector<Vec4i> hierarchy; 

    Canny(src_gray, canny_output, canny_thresh, canny_thresh*2, 3); 

    // Draw rectangle around canny image to also get regions touching the edges. 
    rectangle(canny_output, Point(1, 1), Point(src.cols-2, src.rows-2), Scalar(255)); 
    namedWindow("Canny", CV_WINDOW_AUTOSIZE); 
    imshow("Canny", canny_output); 

    // Find the contours. 
    findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

    // Remove largest Contour, because it represents always the whole image. 
    sort(contours.begin(), contours.end(), cmp_contour_area_less); 
    contours.resize(contours.size()-1); 
    reverse(contours.begin(), contours.end()); 

    // Maximum contour size. 
    int image_pixels(src.cols * src.rows); 
    cout << "image_pixels: " << image_pixels << "\n"; 

    // Filter the contours, leaving just large enough ones. 
    vector<vector<Point> > background_contours; 
    for(size_t i(0); i < contours.size(); ++i) 
    { 
     double area(contourArea(contours[i])); 
     double min_size((size_per_mill/1000.0) * image_pixels); 
     if (area >= min_size) 
     { 
      cout << "Background contour " << i << ") area: " << area << "\n"; 
      background_contours.push_back(contours[i]); 
     } 
    } 

    // Draw large contours. 
    Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3); 
    for(size_t i(0); i < background_contours.size(); ++i) 
    { 
     Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255)); 
     drawContours(drawing, background_contours, i, color, 1, 8, hierarchy, 0, Point()); 
    } 

    namedWindow("Contours", CV_WINDOW_AUTOSIZE); 
    imshow("Contours", drawing); 
} 

void size_callback(int, void*) 
{ 
    Segment(); 
} 

void thresh_callback(int, void*) 
{ 
    Segment(); 
} 

int main(int argc, char* argv[]) 
{ 
    if (argc != 2) 
    { 
     cout << "Please provide an image file.\n"; 
     return -1; 
    } 

    src = imread(argv[1]); 

    cvtColor(src, src_gray, CV_BGR2GRAY); 
    blur(src_gray, src_gray, Size(3,3)); 

    namedWindow("Source", CV_WINDOW_AUTOSIZE); 
    imshow("Source", src); 

    if (!src.data) 
    { 
     cout << "Unable to load " << argv[1] << ".\n"; 
     return -2; 
    } 

    createTrackbar("Canny thresh:", "Source", &canny_thresh, max_canny_thresh, thresh_callback); 
    createTrackbar("Size thresh:", "Source", &size_per_mill, max_size_per_mill, thresh_callback); 

    Segment(); 
    waitKey(0); 
}