web-dev-qa-db-ja.com

バイナリオブジェクト内の穴を埋める

黒いコインの内側にある白い穴を埋めるのに問題があり、黒いコインで0-255のバイナリイメージしか持てません。数回の侵食後にそれらを認識するため... opencvのメソッドのような単純なfloodFillが必要です

これが穴のある私の画像です:

enter image description here

編集:関数のような塗りつぶしは、シードとしてX、Y座標を要求せずに大きなコンポーネントの穴を埋める必要があります...

編集:私はcvDrawContours関数を使用しようとしましたが、大きなものの内側の輪郭を塗りつぶしません。

ここに私のコードがあります:

        CvMemStorage mem = cvCreateMemStorage(0);
        CvSeq contours = new CvSeq();
        CvSeq ptr = new CvSeq();
        int sizeofCvContour = Loader.sizeof(CvContour.class);

        cvThreshold(gray, gray, 150, 255, CV_THRESH_BINARY_INV);

        int numOfContours = cvFindContours(gray, mem, contours, sizeofCvContour, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
        System.out.println("The num of contours: "+numOfContours); //prints 87, ok

        Random Rand = new Random();
        for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
            Color randomColor = new Color(Rand.nextFloat(), Rand.nextFloat(), Rand.nextFloat());
            CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
            cvDrawContours(gray, ptr, color, color, -1, CV_FILLED, 8);
        }
        CanvasFrame canvas6  = new CanvasFrame("drawContours");
        canvas6.showImage(gray);

結果:(各コインの内部にブラックホールがあります)

enter image description here

28
Zaur Guliyev

これを行うには2つの方法があります。

1)輪郭塗りつぶし:

最初に画像を反転し、画像の輪郭を見つけ、黒で塗りつぶして反転します。

des = cv2.bitwise_not(gray)
contour,hier = cv2.findContours(des,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contour:
    cv2.drawContours(des,[cnt],0,255,-1)

gray = cv2.bitwise_not(des)

結果の画像:

enter image description here

2)画像オープニング:

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
res = cv2.morphologyEx(gray,cv2.MORPH_OPEN,kernel)

結果の画像は次のとおりです。

enter image description here

両方のケースに大きな違いはありません。

[〜#〜] nb [〜#〜]:グレー-グレースケール画像、すべてのコードはOpenCV-Pythonにあります

44
Abid Rahman K

単純な膨張と侵食は、ギャップをかなりうまく埋めるだろうと思います。多分これがあなたが探しているものだと思う。

より堅牢なソリューションは、画像全体でエッジ検出を行い、次に円のハフ変換を行うことです。簡単なグーグルは、ハフ変換を使用して円のサイズ不変検出のためのさまざまな言語で利用可能なコードサンプルがあることを示しています。

ハフ変換を使用する利点は、アルゴリズムが実際にすべての円のサイズと位置の推定値を提供するため、そのモデルに基づいて理想的な画像を再構築できることです。また、特にここでの入力画像の品質を考慮すると、オーバーラップに対して非常に堅牢である必要があります(つまり、誤検知の心配が少ないため、結果のしきい値を下げることができます)。

5
Elias Vasylenko

モルフォロジー画像再構成のアプリケーションである Fillhole transform を探しているかもしれません。

この変換は、隣接するコインのグループ間のすべての穴を埋めることを犠牲にしてでも、コインの穴を埋めます。他のポスターによって提案されたハフ空間またはオープニングベースのソリューションは、おそらくより良い高レベルの認識結果を与えるでしょう。

5
thiton

私は適切なimfill関数(Matlabの関数として)を見つけるためにインターネットを探していましたが、CでOpenCVを使用しています。いくつかの調査の後、私は最終的に解決策を思いつきました:

IplImage* imfill(IplImage* src)
{
    CvScalar white = CV_RGB( 255, 255, 255 );

    IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3);
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contour = 0;

    cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
    cvZero( dst );

    for( ; contour != 0; contour = contour->h_next )
    {
        cvDrawContours( dst, contour, white, white, 0, CV_FILLED);
    }

    IplImage* bin_imgFilled = cvCreateImage(cvGetSize(src), 8, 1);
    cvInRangeS(dst, white, white, bin_imgFilled);

    return bin_imgFilled;
}

このため: 元のバイナリイメージ

結果は次のとおりです。 最終バイナリイメージ

その秘Drawは、cvDrawContours関数のパラメーター設定にあります。cvDrawContours(dst、contour、white、white、0、CV_FILLED);

  • dst =宛先イメージ
  • contour =最初の輪郭へのポインタ
  • 白=輪郭の塗りつぶしに使用される色
  • 0 =描かれた輪郭の最大レベル。 0の場合、輪郭のみが描画されます
  • CV_FILLED =輪郭が描かれる線の太さ。負の場合(たとえば、= CV_FILLED)、輪郭の内部が描画されます。

詳細はopenCVのドキュメントをご覧ください。

おそらくバイナリイメージとして「dst」を直接取得する方法がありますが、バイナリ値でcvDrawContours関数を使用する方法を見つけることができませんでした。

1
Jeremy.S

cvFindContours() 関数を使用してみてください。これを使用して、接続されているコンポーネントを見つけることができます。適切なパラメータを使用すると、この関数は、接続された各コンポーネントの輪郭を含むリストを返します。

穴を表す輪郭を見つけます。次に、 cvDrawContours() を使用して、選択した輪郭を前景色で塗りつぶし、穴を閉じます。

1
bubble

誰かがcppの実装を探している場合-

            std::vector<std::vector<cv::Point> > contours_vector;

            cv::findContours(input_image, contours_vector, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

            cv::Mat contourImage(input_image.size(), CV_8UC1, cv::Scalar(0));
            for ( ushort contour_index = 0; contour_index < contours_vector.size(); contour_index++) {
                cv::drawContours(contourImage, contours_vector, contour_index, cv::Scalar(255), -1);
            }

            cv::imshow("con", contourImage);
            cv::waitKey(0);

enter image description here

enter image description here

1
infoclogged

オブジェクトに触れたり、混雑したりすると、輪郭と数学のモロフォロジーの開口部を使用する際に問題が発生すると思います。代わりに、次の簡単なソリューションが見つかり、テストされます。これは非常にうまく機能しており、この画像だけでなく、他の画像でも機能します。

http://blogs.mathworks.com/steve/2008/08/05/filling-small-holes/ に示されている手順は(最適化された)ここにあります

let I:入力画像

1. filled_I = floodfill(I). // fill every hole in the image.
2. inverted_I = invert(I)`.   
3. holes_I = filled_I AND inverted_I. // finds all holes 
4. cc_list = connectedcomponent(holes_I) // list of all connected component in holes_I.
5. holes_I = remove(cc_list,holes_I, smallholes_threshold_size) // remove all holes from holes_I having size > smallholes_threshold_size.
6. out_I = I OR holes_I. // fill only the small holes.

要するに、アルゴリズムは、すべての穴を見つけ、大きな穴を削除し、元の画像にのみ小さな穴を書き込むだけです。

1
Faroq AL-Tam