opencvで細線化

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
scottie
記事: 2
登録日時: 6年前

opencvで細線化

#1

投稿記事 by scottie » 6年前

Microsoft Visual Studio Express 2013
opencv2.4.9

↓を書き換えています

コード:

using namespace cv;
void thinningIte(Mat& img, int pattern){

	Mat del_marker = Mat::ones(img.size(), CV_8UC1);
	int x, y;

	for (y = 1; y < img.rows - 1; ++y) {
		for (x = 1; x < img.cols - 1; ++x) {

			int v9, v2, v3;
			int v8, v1, v4;
			int v7, v6, v5;

			v1 = img.data[y   * img.step + x   * img.elemSize()];
			v2 = img.data[(y - 1) * img.step + x   * img.elemSize()];
			v3 = img.data[(y - 1) * img.step + (x + 1) * img.elemSize()];
			v4 = img.data[y   * img.step + (x + 1) * img.elemSize()];
			v5 = img.data[(y + 1) * img.step + (x + 1) * img.elemSize()];
			v6 = img.data[(y + 1) * img.step + x   * img.elemSize()];
			v7 = img.data[(y + 1) * img.step + (x - 1) * img.elemSize()];
			v8 = img.data[y   * img.step + (x - 1) * img.elemSize()];
			v9 = img.data[(y - 1) * img.step + (x - 1) * img.elemSize()];

			int S = (v2 == 0 && v3 == 1) + (v3 == 0 && v4 == 1) +
				(v4 == 0 && v5 == 1) + (v5 == 0 && v6 == 1) +
				(v6 == 0 && v7 == 1) + (v7 == 0 && v8 == 1) +
				(v8 == 0 && v9 == 1) + (v9 == 0 && v2 == 1);

			int N = v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9;

			int m1 = 0, m2 = 0;

			if (pattern == 0) m1 = (v2 * v4 * v6);
			if (pattern == 1) m1 = (v2 * v4 * v8);

			if (pattern == 0) m2 = (v4 * v6 * v8);
			if (pattern == 1) m2 = (v2 * v6 * v8);

			if (S == 1 && (N >= 2 && N <= 6) && m1 == 0 && m2 == 0)
				del_marker.data[y * del_marker.step + x * del_marker.elemSize()] = 0;
		}
	}
	img &= del_marker;
}

void thinning(const Mat& src, Mat& dst){
	dst = src.clone();
	dst /= 255;         // 0は0 , 1以上は1に変換される

	Mat prev = Mat::zeros(dst.size(), CV_8UC1);
	Mat diff;

	do {
		thinningIte(dst, 0);
		thinningIte(dst, 1);
		absdiff(dst, prev, diff);
		dst.copyTo(prev);
	} while (countNonZero(diff) > 0);

	dst *= 255;
}

int main(){
	Mat img = imread("a.bmp");

	Mat img2;
	cvtColor(img, img2, CV_BGR2GRAY);
	threshold(img2, img2, 10, 255, CV_THRESH_BINARY);

	thinning(img2, img2);

	imshow("src", img);
	imshow("dst", img2);
	waitKey();
	return 0;
}
41行目
void thinningのdo while
をどう書き換えればいいのか教えてください
v1~v9の書き換えはあってるのでしょうか

コード:

void thinningIte(IplImage *Img_nichi, int pattern){
    IplImage *Img_sai;
    Img_sai = cvCreateImage(cvGetSize(Img_nichi), IPL_DEPTH_8U,1);
 
    for (int y = 1; y<Img_nichi->width - 1; y++){
        for (int x = 1; x<Img_nichi->width - 1; x++){
            int v9, v2, v3;
            int v8, v1, v4;
            int v7, v6, v5;
 
            v1 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y + 0) * Img_nichi->widthStep);
            v2 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y - 1) * Img_nichi->widthStep);
            v3 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y - 1) * Img_nichi->widthStep);
            v4 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y + 0) * Img_nichi->widthStep);
            v5 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y + 1) * Img_nichi->widthStep);
            v6 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y + 1) * Img_nichi->widthStep);
            v7 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y + 1) * Img_nichi->widthStep);
            v8 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y + 0) * Img_nichi->widthStep);
            v9 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y - 1) * Img_nichi->widthStep);
 
            int S = (v2 == 0 && v3 == 1) + (v3 == 0 && v4 == 1) +
                (v4 == 0 && v5 == 1) + (v5 == 0 && v6 == 1) +
                (v6 == 0 && v7 == 1) + (v7 == 0 && v8 == 1) +
                (v8 == 0 && v9 == 1) + (v9 == 0 && v2 == 1);
 
            int N = v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9;
 
            int m1 = 0, m2 = 0;
 
            if (pattern == 0) m1 = (v2 * v4 * v6);
            if (pattern == 1) m1 = (v2 * v4 * v8);
 
            if (pattern == 0) m2 = (v4 * v6 * v8);
            if (pattern == 1) m2 = (v2 * v6 * v8);
 
            if (S == 1 && (N >= 2 && N <= 6) && m1 == 0 && m2 == 0)
                *(uchar*)(Img_sai->imageData + x + y * Img_sai->widthStep) = 0;
 
        }
    }
    //Img_nichi &= Img_sai;
}
 
void thinning(IplImage *Img_1,IplImage *Img_2){
    Img_2 = cvCreateImage(cvGetSize(Img_1), IPL_DEPTH_8U, 3);
    cvCopy(Img_1, Img_2);
    do {
        thinningIte(Img_2, 0);
        thinningIte(Img_2, 1);
    } while ();
 
}
 
int main(int argc, char* argv[]){
    IplImage *Img_orig; //元画像
    IplImage *Img_gray; //グレースケール
    IplImage *Img_nichi; //2値
    IplImage *Img_sai0;
    IplImage *Img_sai1;
 
    int W, H; //widthとheight
    int x, y; //カウント
    int sikichi = 1; //閾値
 
    //画像の読み込み
    Img_orig = cvLoadImage("a.jpg", 1);
 
    W = Img_orig->width;//幅
    H = Img_orig->height;//高さ
 
    //画像リソースの確保
    Img_gray  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_nichi = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_sai0  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_sai1  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
 
    //グレースケール化
    for (y=0 ; y<H ; y++){
        for (x=0 ; x<W ; x++){
            *(Img_gray->imageData + x + y * W) =
                (char)((0.114 * *(uchar*)(Img_orig->imageData + (3 * x) + y * Img_orig->widthStep)) +
                (0.587 * *(uchar*)(Img_orig->imageData + (3 * x + 1) + y * Img_orig->widthStep)) +
                (0.299 * *(uchar*)(Img_orig->imageData + (3 * x + 2) + y * Img_orig->widthStep)));
        }
    }
 
    //2値化
    for (y=0 ; y<H ; y++){
        for (x=0 ; x<W ; x++){
            if (*(Img_gray->imageData + x + y*Img_gray->width) > sikichi){ //閾値より大きければ
                *(Img_nichi->imageData + x + y*Img_nichi->width) = 0; //白
                *(Img_sai0->imageData + x + y*Img_sai0->width) = 0;
            }
            else{                                                        //それ以外
                *(Img_nichi->imageData + x + y*Img_nichi->width) = 255; //黒
                *(Img_sai0->imageData + x + y*Img_sai0->width) = 1;
            }
        }
    }
 
    //細線化
    thinning(Img_sai0, Img_sai1);
 
    //0と1を0と255にする
    for (y = 0; y<H; y++){
        for (x = 0; x<W; x++){
            if (*(Img_sai1->imageData + x + y*Img_sai1->width) > 0){ 
                *(Img_sai1->imageData + x + y*Img_sai1->width) = 255;
            }
        }
    }
 
    //画像の表示
    cvShowImage("元画像", Img_orig);
    cvShowImage("グレースケール", Img_gray);
    cvShowImage("2値", Img_nichi);
    cvShowImage("2値", Img_sai1);
 
    //画像の保存
    cvSaveImage("No_5a.bmp", Img_gray);
    cvSaveImage("No_5b.bmp", Img_nichi);
    cvSaveImage("No_5c.bmp", Img_sai1);
 
    //キー入力待機
    cvWaitKey(0);
 
    //ウィンドウの破棄
    cvDestroyAllWindows();
 
    //画像リソースの解放
    cvReleaseImage(&Img_orig);
    cvReleaseImage(&Img_gray);
    cvReleaseImage(&Img_nichi);
    cvReleaseImage(&Img_sai1);
 
    return 0;
}
参考
http://www.cellstat.net/thinning/
最後に編集したユーザー scottie on 2017年3月24日(金) 15:44 [ 編集 5 回目 ]

みえ
記事: 23
登録日時: 6年前

Re: opencvで細線化

#2

投稿記事 by みえ » 6年前

書き換えとありますが、何のための書き換えなのでしょうか。とりあえず、「何らかの制限で C++ が使えないため、C 言語で書き直す必要がある」という想定で考えてみました。
下記に示すコードがもし scottie さんの要件に合わなければ教えてください。
scottie さんが書きました:41行目
void thinningのdo while
をどう書き換えればいいのか教えてください
v1~v9の書き換えはあってるのでしょうか
こちらの質問にまず簡単に回答しますと、元ネタの「2値画像の細線化」で使われているabsdiff をcvAbsDiffに、そしてcountNonZero を cvCountNonZeroに置き換えればいいと思います。
v1 ~ v9 の部分は、とりあえずそのままでも問題ありません。

ただし、残念ながら do while 部分を書き足しただけでは期待通りに動きません。質問されている箇所以外の部分で以下の点を直す必要がありました。

(1) グレースケール化、2 値化のところでピクセルがずれる
ピクセル代入や、2 値化での比較で、左辺における幅の指定が W や width になっているため、画像にパディングがあるときに正しい位置に代入されません。左辺の幅には widthStep を使う必要があります。
が、そもそも IplImage のピクセル操作においては、生の imageData にアクセスするより CV_IMAGE_ELEM マクロを使ったほうがコードがすっきりすると思いますし、ミスも防げます。

(2) 2 値化における比較、代入が正しくない
sikichi との比較で、左辺は符号なし型にキャストする必要があります。今のままだと、黒 (= 0) と白 (= 255 = -1) が同じ値に 2 値化されてしまいます。
あと、Img_nichi に代入している値が逆だと思います。白が 255、黒が 0 ですよね。
さらに、閾値 1 は厳しすぎると思います。元の記事のように 10 ぐらいの方がいい結果が得られると思います。

(3) thinningIte の外側のループの上限が width
height の間違いだと思います。

(4) thinning における Img_2 の初期化が正しくない
Img_2 を 3 チャンネルで作成していますが、Img_1 は 1 チャンネルなのでコピーできません。そもそも、呼び出し時に初期化済の Img_sai1 を渡しているので、cvCreateImage は不要です。
さらに言えば、cvCreateImage してから cvCopy する代わりに cvClone を使えば一発でクローンできるので、thinning は結果の Img_2 を戻り値で返すようにした方がコードが綺麗になると思います。

(5) thinningIte の大事な部分が 2 つ抜けている
まず、Img_sai は 1 で初期化する必要があるので cvCreateImage だけでは不十分です。cvSet で 1 をセットしました。
最後の Img_nichi &= Img_sai; がコメントアウトされていますが、これも必要な処理です。C 言語だと cvAnd が使えます。

(6) オブジェクトのリーク
thinningIte の Img_sai、main の Img_sai0 がリリースされません。

修正後のコードは以下の通りです。

コード:

#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/highgui/highgui_c.h>

void thinningIte(IplImage *Img_nichi, int pattern){
    IplImage *Img_sai;
    Img_sai = cvCreateImage(cvGetSize(Img_nichi), IPL_DEPTH_8U,1);

    CvScalar ones = {1};
    cvSet(Img_sai, ones, NULL);

    for (int y = 1; y<Img_nichi->height - 1; y++){
        for (int x = 1; x<Img_nichi->width - 1; x++){
            int v9, v2, v3;
            int v8, v1, v4;
            int v7, v6, v5;

            v1 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y + 0) * Img_nichi->widthStep);
            v2 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y - 1) * Img_nichi->widthStep);
            v3 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y - 1) * Img_nichi->widthStep);
            v4 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y + 0) * Img_nichi->widthStep);
            v5 = *(uchar*)(Img_nichi->imageData + (x + 1) + (y + 1) * Img_nichi->widthStep);
            v6 = *(uchar*)(Img_nichi->imageData + (x + 0) + (y + 1) * Img_nichi->widthStep);
            v7 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y + 1) * Img_nichi->widthStep);
            v8 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y + 0) * Img_nichi->widthStep);
            v9 = *(uchar*)(Img_nichi->imageData + (x - 1) + (y - 1) * Img_nichi->widthStep);

            int S = (v2 == 0 && v3 == 1) + (v3 == 0 && v4 == 1) +
                (v4 == 0 && v5 == 1) + (v5 == 0 && v6 == 1) +
                (v6 == 0 && v7 == 1) + (v7 == 0 && v8 == 1) +
                (v8 == 0 && v9 == 1) + (v9 == 0 && v2 == 1);

            int N = v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9;

            int m1 = 0, m2 = 0;

            if (pattern == 0) m1 = (v2 * v4 * v6);
            if (pattern == 1) m1 = (v2 * v4 * v8);

            if (pattern == 0) m2 = (v4 * v6 * v8);
            if (pattern == 1) m2 = (v2 * v6 * v8);

            if (S == 1 && (N >= 2 && N <= 6) && m1 == 0 && m2 == 0)
                *(uchar*)(Img_sai->imageData + x + y * Img_sai->widthStep) = 0;

        }
    }
    cvAnd(Img_nichi, Img_sai, Img_nichi, NULL);
    cvReleaseImage(&Img_sai);
}

void thinning(IplImage *Img_1,IplImage *Img_2){
    cvCopy(Img_1, Img_2, 0);

    IplImage *prev = cvCreateImage(cvGetSize(Img_2), IPL_DEPTH_8U, 1);
    IplImage *diff = cvCreateImage(cvGetSize(Img_2), IPL_DEPTH_8U, 1);

    do {
        thinningIte(Img_2, 0);
        thinningIte(Img_2, 1);
        cvAbsDiff(Img_2, prev, diff);
        cvCopy(Img_2, prev, NULL);
    } while (cvCountNonZero(diff) > 0);

    cvReleaseImage(&diff);
    cvReleaseImage(&prev);
}

int main(int argc, char* argv[]){
    if (argc < 2) return 1;

    IplImage *Img_orig; //元画像
    IplImage *Img_gray; //グレースケール
    IplImage *Img_nichi; //2値
    IplImage *Img_sai0;
    IplImage *Img_sai1;

    int W, H; //widthとheight
    int x, y; //カウント
    int sikichi = 10; //閾値

    //画像の読み込み
    Img_orig = cvLoadImage(argv[1], 1);

    W = Img_orig->width;//幅
    H = Img_orig->height;//高さ

    //画像リソースの確保
    Img_gray  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_nichi = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_sai0  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_sai1  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒

    //グレースケール化
    for (y=0 ; y<H ; y++){
        for (x=0 ; x<W ; x++){
            *(Img_gray->imageData + x + y * Img_gray->widthStep) =
                (char)((0.114 * *(uchar*)(Img_orig->imageData + (3 * x) + y * Img_orig->widthStep)) +
                (0.587 * *(uchar*)(Img_orig->imageData + (3 * x + 1) + y * Img_orig->widthStep)) +
                (0.299 * *(uchar*)(Img_orig->imageData + (3 * x + 2) + y * Img_orig->widthStep)));
        }
    }

    //2値化
    for (y=0 ; y<H ; y++){
        for (x=0 ; x<W ; x++){
            if (*(uchar*)(Img_gray->imageData + x + y*Img_gray->widthStep) > sikichi){ //閾値より大きければ
                *(Img_nichi->imageData + x + y*Img_nichi->widthStep) = 255; //白
                *(Img_sai0->imageData + x + y*Img_sai0->widthStep) = 1;
            }
            else{                                                        //それ以外
                *(Img_nichi->imageData + x + y*Img_nichi->widthStep) = 0; //黒
                *(Img_sai0->imageData + x + y*Img_sai0->widthStep) = 0;
            }
        }
    }

    //細線化
    thinning(Img_sai0, Img_sai1);

    //0と1を0と255にする
    for (y = 0; y<H; y++){
        for (x = 0; x<W; x++){
            if (*(Img_sai1->imageData + x + y*Img_sai1->width) > 0){
                *(Img_sai1->imageData + x + y*Img_sai1->width) = 255;
            }
        }
    }

    //画像の表示
    cvShowImage("元画像", Img_orig);
    cvShowImage("グレースケール", Img_gray);
    cvShowImage("2値 (細線化前)", Img_nichi);
    cvShowImage("2値 (細線化後)", Img_sai1);

    //画像の保存
    cvSaveImage("No_5a.bmp", Img_gray, 0);
    cvSaveImage("No_5b.bmp", Img_nichi, 0);
    cvSaveImage("No_5c.bmp", Img_sai1, 0);

    //キー入力待機
    cvWaitKey(0);

    //ウィンドウの破棄
    cvDestroyAllWindows();

    //画像リソースの解放
    cvReleaseImage(&Img_orig);
    cvReleaseImage(&Img_gray);
    cvReleaseImage(&Img_nichi);
    cvReleaseImage(&Img_sai0);
    cvReleaseImage(&Img_sai1);

    return 0;
}
結果は添付画像のようになりました。
添付ファイル
results-googlelogo.png
results-googlelogo.png (18.11 KiB) 閲覧数: 4076 回
最後に編集したユーザー みえ on 2017年3月25日(土) 13:09 [ 編集 4 回目 ]

みえ
記事: 23
登録日時: 6年前

Re: opencvで細線化

#3

投稿記事 by みえ » 6年前

ところで、グレースケール化や 2 値化といった処理をループで書き下しているのはなぜですか?
それぞれ cvCvtColor と cvThreshold で実現可能なので、もし使えるのであれば OpenCV の API に頼った方が楽だし安全だと思います。
使える API を使用し、また、不要な変数などを取り除いたコードはこちらです。ご参考までに。

コード:

#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/highgui/highgui_c.h>

void thinningIte(IplImage *Img_nichi, int pattern){
    IplImage *Img_sai = cvCreateImage(cvGetSize(Img_nichi), IPL_DEPTH_8U, 1);
    CvScalar ones = {1};
    cvSet(Img_sai, ones, NULL);

    for (int y = 1; y<Img_nichi->height - 1; y++){
        for (int x = 1; x<Img_nichi->width - 1; x++){
            int v9, v2, v3;
            int v8, v1, v4;
            int v7, v6, v5;

            v1 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 0, x + 0);
            v2 = CV_IMAGE_ELEM(Img_nichi, uchar, y - 1, x + 0);
            v3 = CV_IMAGE_ELEM(Img_nichi, uchar, y - 1, x + 1);
            v4 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 0, x + 1);
            v5 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 1, x + 1);
            v6 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 1, x + 0);
            v7 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 1, x - 1);
            v8 = CV_IMAGE_ELEM(Img_nichi, uchar, y + 0, x - 1);
            v9 = CV_IMAGE_ELEM(Img_nichi, uchar, y - 1, x - 1);

            int S = (v2 == 0 && v3 == 1) + (v3 == 0 && v4 == 1) +
                    (v4 == 0 && v5 == 1) + (v5 == 0 && v6 == 1) +
                    (v6 == 0 && v7 == 1) + (v7 == 0 && v8 == 1) +
                    (v8 == 0 && v9 == 1) + (v9 == 0 && v2 == 1);

            int N = v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9;

            int m1 = 0, m2 = 0;

            if (pattern == 0) m1 = (v2 * v4 * v6);
            if (pattern == 1) m1 = (v2 * v4 * v8);

            if (pattern == 0) m2 = (v4 * v6 * v8);
            if (pattern == 1) m2 = (v2 * v6 * v8);

            if (S == 1 && (N >= 2 && N <= 6) && m1 == 0 && m2 == 0)
                CV_IMAGE_ELEM(Img_sai, uchar, y, x) = 0;
        }
    }
    cvAnd(Img_nichi, Img_sai, Img_nichi, NULL);
    cvReleaseImage(&Img_sai);
}

IplImage *thinning(IplImage *Img_1){
    IplImage *white = cvCreateImage(cvGetSize(Img_1), IPL_DEPTH_8U,1);
    CvScalar full_bits = {0xff};
    cvSet(white, full_bits, NULL);

    IplImage *Img_2 = cvCloneImage(Img_1);
    cvDiv(Img_2, white, Img_2, 1);

    IplImage *prev = cvCreateImage(cvGetSize(Img_2), IPL_DEPTH_8U, 1);
    IplImage *diff = cvCreateImage(cvGetSize(Img_2), IPL_DEPTH_8U, 1);

    do {
        thinningIte(Img_2, 0);
        thinningIte(Img_2, 1);
        cvAbsDiff(Img_2, prev, diff);
        cvCopy(Img_2, prev, NULL);
    } while (cvCountNonZero(diff) > 0);

    cvMul(Img_2, white, Img_2, 1);

    cvReleaseImage(&white);
    cvReleaseImage(&diff);
    cvReleaseImage(&prev);
    return Img_2;
}

int main(int argc, char* argv[]){
    if (argc < 2) return 1;

    IplImage *Img_orig; //元画像
    IplImage *Img_gray; //グレースケール
    IplImage *Img_nichi; //2値
    IplImage *Img_sai;

    int W, H; //widthとheight

    //画像の読み込み
    Img_orig = cvLoadImage(argv[1], 1);

    W = Img_orig->width;//幅
    H = Img_orig->height;//高さ

    //画像リソースの確保
    Img_gray  = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒
    Img_nichi = cvCreateImage(cvSize(W, H), IPL_DEPTH_8U, 1); //白黒

    //グレースケール化
    cvCvtColor(Img_orig, Img_gray, CV_BGR2GRAY);

    //2値化
    cvThreshold(Img_gray, Img_nichi, 10, 255, CV_THRESH_BINARY);

    //細線化
    Img_sai = thinning(Img_nichi);

    //画像の表示
    cvShowImage("元画像", Img_orig);
    cvShowImage("グレースケール", Img_gray);
    cvShowImage("2値 (細線化前)", Img_nichi);
    cvShowImage("2値 (細線化後)", Img_sai);

    //画像の保存
    cvSaveImage("No_5a.bmp", Img_gray, 0);
    cvSaveImage("No_5b.bmp", Img_nichi, 0);
    cvSaveImage("No_5c.bmp", Img_sai, 0);

    //キー入力待機
    cvWaitKey(0);

    //ウィンドウの破棄
    cvDestroyAllWindows();

    //画像リソースの解放
    cvReleaseImage(&Img_orig);
    cvReleaseImage(&Img_gray);
    cvReleaseImage(&Img_nichi);
    cvReleaseImage(&Img_sai);

    return 0;
}

scottie
記事: 2
登録日時: 6年前

Re: opencvで細線化

#4

投稿記事 by scottie » 6年前

>>みえ様
ありがとうございます;;
すいません説明不足でした。
いざ何か作るときにAPIがなければ困るのだから決められた指定された最低限のcv○○以外は使用せずに自分の気になったもの技術の実装にチャレンジしてみよう!
といった試練を出され困っていました(成績評価などの課題ではない)

W,Hなんかは横着して使ってましたが
きちんと正しい意味で使わないとぐっちゃぐちゃで意味不明なものになっていきますね・・・

何気なく使っていたものにこんなに手こずるとは・・・
cvAndとcvAbsDiffをこれから書き換えていこうと思います(汗)
できるだろうかw^^:
調べてもAPIでの実装しか出てこない分手こずります
更に何か追加することも考えたら2値化やグレースケールも関数化したほうが良いですね

みえ
記事: 23
登録日時: 6年前

Re: opencvで細線化

#5

投稿記事 by みえ » 6年前

なるほど。そういう状況でしたか。API が実際にどのような計算をしているのかを知るために、自分で API と同じ実装を書いてみるというのはいい試みだと思います。OpenCV に関して言えば、オープンソースなので、実装が分からないときには https://github.com/opencv/opencv でコードを検索すれば簡単に答えが見つかります。

cvAnd も cvAbsDiff も基本的にはピクセルをループしてand 演算や引き算をするだけなので、今まで scottie さんが書いたことと大きく変わらないと思います。
その上で、自分でループを書くのであればループの数を減らす工夫ができると思います。すぐに思いつくのは、グレースケール化と 2 値化を一回のループにまとめられるところと、cvAbsDiff するときに同時に non-zero のピクセルを数えて cvCountNonZero を省略できるところでしょうかね。

返信

“C言語何でも質問掲示板” へ戻る