2013-01-08 168 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); 
}