7

JavaCV (OpenCV ラッパー) を使用してコイン検出を行っていますが、コインが接続されているときに少し問題があります。これらのコインを分離するためにそれらを侵食しようとすると、円の形が失われ、各コイン内のピクセルを数えようとすると、一部のコインがそれより大きいコインとして誤ってカウントされる可能性があります。私がやりたいことは、最初にそれらを再形成して円のようにし (そのコインの半径と同じ)、次にそれらの内部のピクセルをカウントすることです。

ここに私のしきい値画像があります:ここに画像の説明を入力

そして、侵食された画像は次のとおりです。ここに画像の説明を入力

助言がありますか?または、コイン間の橋を架けるより良い方法はありますか?

4

5 に答える 5

11

これは、私が最近、寒天プレートで増殖している細菌コロニーを分離する必要があった問題に似ています。しきい値処理された画像で距離変換を実行しました(この場合、反転する必要があります)。次に、距離マップのピークを見つけました(膨張した距離マップと距離マップの差を計算し、ゼロ値を見つけることにより)。次に、各ピークを円 (コイン) の中心とし、距離マップのピークの値を円の半径と仮定しました。

このパイプライン後の画像の結果は次のとおりです。 距離変換作品

私はOpenCVとc ++を初めて使用するため、コードはおそらく非常に面倒ですが、私はそれを行いました:

int main( int argc, char** argv ){

    cv::Mat objects, distance,peaks,results;
    std::vector<std::vector<cv::Point> > contours;

    objects=cv::imread("CUfWj.jpg");
    objects.copyTo(results);
    cv::cvtColor(objects, objects, CV_BGR2GRAY);
    //THIS IS THE LINE TO BLUR THE IMAGE CF COMMENTS OF THIS POST
    cv::blur( objects,objects,cv::Size(3,3));
    cv::threshold(objects,objects,125,255,cv::THRESH_BINARY_INV);


    /*Applies a distance transform to "objects".
     * The result is saved in "distance" */
    cv::distanceTransform(objects,distance,CV_DIST_L2,CV_DIST_MASK_5);

    /* In order to find the local maxima, "distance"
     * is subtracted from the result of the dilatation of
     * "distance". All the peaks keep the save value */
    cv::dilate(distance,peaks,cv::Mat(),cv::Point(-1,-1),3);
    cv::dilate(objects,objects,cv::Mat(),cv::Point(-1,-1),3);

    /* Now all the peaks should be exactely 0*/
    peaks=peaks-distance;

    /* And the non-peaks 255*/
    cv::threshold(peaks,peaks,0,255,cv::THRESH_BINARY);
    peaks.convertTo(peaks,CV_8U);

    /* Only the zero values of "peaks" that are non-zero
     * in "objects" are the real peaks*/
    cv::bitwise_xor(peaks,objects,peaks);

    /* The peaks that are distant from less than
     * 2 pixels are merged by dilatation */
    cv::dilate(peaks,peaks,cv::Mat(),cv::Point(-1,-1),1);

    /* In order to map the peaks, findContours() is used.
     * The results are stored in "contours" */
    cv::findContours(peaks, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
    /* The next steps are applied only if, at least,
     * one contour exists */
    cv::imwrite("CUfWj2.jpg",peaks);
    if(contours.size()>0){

        /* Defines vectors to store the moments of the peaks, the center
         * and the theoritical circles of the object of interest*/
        std::vector <cv::Moments> moms(contours.size());
        std::vector <cv::Point> centers(contours.size());
        std::vector<cv::Vec3f> circles(contours.size());
        float rad,x,y;
        /* Caculates the moments of each peak and then the center of the peak
         * which are approximatively the center of each objects of interest*/

        for(unsigned int i=0;i<contours.size();i++) {
            moms[i]= cv::moments(contours[i]);
            centers[i]= cv::Point(moms[i].m10/moms[i].m00,moms[i].m01/moms[i].m00);
            x= (float) (centers[i].x);
            y= (float) (centers[i].y);
            if(x>0 && y>0){
                rad= (float) (distance.at<float>((int)y,(int)x)+1);
                circles[i][0]= x;
                circles[i][3]= y;
                circles[i][2]= rad;
                cv::circle(results,centers[i],rad+1,cv::Scalar( 255, 0,0 ), 2, 4, 0 );
            }
        }
        cv::imwrite("CUfWj2.jpg",results);
    }

    return 1;
}
于 2012-04-25T22:32:22.330 に答える
5

侵食する必要はありません。次のパラメータの適切なセットですcvHoughCircles()

ここに画像の説明を入力

この画像を生成するために使用されたコードは、私の別の投稿Detecting Circlesからのもので、次のパラメーターがあります。

CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->height/12, 80, 26);
于 2012-04-25T13:16:56.400 に答える
2

OpenCV には HoughCircles() という関数があり、異なる円を分離せずにケースに適用できます。JavaCV から呼び出すことはできますか? もしそうなら、それはあなたが望むこと(円の検出とカウント)を行い、分離の問題を回避します。

ポイントは、最初に円を分離せずに正確に検出することです。他のアルゴリズム (テンプレート マッチングなど) を一般化されたハフ変換の代わりに使用できますが、コインのさまざまなサイズを考慮する必要があります。

于 2012-04-25T10:21:34.387 に答える
1

侵食ベースのオブジェクト認識の通常のアプローチは、侵食された画像の連続領域にラベルを付け、元の画像の領域と一致するまでそれらを再成長させることです。ただし、あなたの場合はハフサークルの方が良いアイデアです。

于 2012-04-26T11:33:13.110 に答える
0

結合されたコインを検出した後、形態学的操作を適用して領域を「間違いなくコイン」と「間違いなくコイン」に分類し、距離変換を適用してから、流域を実行して境界を決定することをお勧めします。このシナリオは、実際には OpenCV の流域アルゴリズムのデモンストレーション例です。おそらく、この質問に応えて作成されたものです。

于 2014-07-23T12:58:17.693 に答える