6

名刺をセグメント化し、背景色で分割して、さまざまな関心領域として扱うようにしています。

たとえば、この種のカード: サンプル名刺

背景色が2つあるので、2つの画像に分割できるはずです。これに取り組む方法について何か提案はありますか?輪郭分析を試してみましたが、あまり成功しませんでした。

その他のカード例: ここに画像の説明を入力してください

このカードは、2色しかないのに3つの部分があるので、3つのセグメンテーションを与える必要があります(2色でも大丈夫ですが)。

ここに画像の説明を入力してください

上記のカードは、1つの背景色であるため、1つのセグメンテーションのみを提供する必要があります。

私はまだグラデーションの背景について考えようとはしていません。

4

2 に答える 2

9

他のカードの見た目にもよりますが、すべての画像がその高品質であれば、それほど難しくはありません。

投稿した例では、境界線のピクセルの色(左端の列、右端の列、最初の行、最後の行)を収集し、見つけたものを可能な背景色として扱うことができます。おそらく、ほぼ同じ色のピクセルが十分にあるかどうかを確認してください。ある種の距離測定が必要です。簡単な解決策の1つは、RGB色空間でユークリッド距離を使用することです。

より一般的な解決策は、画像全体の色ヒストグラムでクラスターを見つけ、全体のピクセル量のx%を超えるすべての色を背景色として扱うことです。ただし、背景として定義するものは、達成したいことと画像の外観によって異なります。

さらに提案が必要な場合は、さらに画像を投稿し、画像のどの部分を背景色として検出し、どの部分を背景色として検出しないかをタグ付けすることができます。

-

編集:2つの新しい画像も同じパターンを示しています。背景色は画像の大部分を占め、ノイズやカラーグラデーションはありません。したがって、単純なアプローチは次のようになります。

このアプローチで機能しない例がある場合は、それらを投稿してください。

于 2013-01-08T20:12:27.707 に答える
0

色のグラデーションが含まれる背景を見つけるためのアプローチとして、cannyを使用できます。次のコード(Androidではありませんが、移植しても結果は同じになるはずです)は、これまでに投稿した3つのサンプル画像で正常に機能します。これで動作しない他の画像がある場合は、お知らせください。

#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);
}
于 2013-01-12T12:01:20.527 に答える