序文
OpenCVには独自に接続ドメインを検索する機能があるようですが、私が使っているバージョンにはその機能がないので、
接続ドメインを検索するにはorzと書く必要があります。
Two-Pass(2パス走査方式)
種子の充填
このブロガーのブログにアクセスして、2 つのアルゴリズムの原理を確認してください。
実装プロセス
この記事では、2 番目の方法であるシード充填法を使用する必要があります。
- パラメータ マットと入力 説明: これはバイナリ イメージです。値は 0 または 255 です。0 (黒) は背景領域を表し、255 (白) はマテリアル領域を表します。
- 関数 labelmark は、2 つの for ループ層を使用して Mat 入力行列を走査します。
内側のループには 2 つのシリアル if ステートメント ブロックがあります。
// 第一个防止 fill_4 函数递归次数太大,内存不够。
if((input.at<unsigned char>(i, j) != 255 && input.at<unsigned char>(i, j) != 0))
//(2)第二个就是实现四邻域的递归判断
if (input.at<unsigned char>(i,j)==255)
- int labelnum;
ラベル値。テスト時の区別を容易にするため、初期値は 1 であり、毎回 10 ずつ増加します。 - input.at(i, j) = labelnum + 50;
50 を足すのはグレーの値を少し大きくするためでもあるので、問題ありません。 - コードの残りの部分はコメントで十分です。
コード
void fill_4(int x, int y, int count, Mat& input, int & jishu) {
//cout << "x = "<< x << ", y = " << y <<", count = "<< count << endl;
jishu++;
if (x-1<=0 || x+1 >=319 || y-1<=0 ||y+1>=319) // 没有考虑四边,偷懒先把四边就设置为0了。
{
return;
}
if (input.at<unsigned char>(x-1, y) == 255) {
input.at<unsigned char>(x-1, y) = count + 50;
if (jishu == 2000)
{
return;
}
fill_4(x-1, y, count, input, jishu);
}
if (input.at<unsigned char>(x, y-1) == 255) {
input.at<unsigned char>(x, y-1) = count + 50;
if (jishu == 2000)
{
return;
}
fill_4(x, y-1, count, input, jishu);
}
if (input.at<unsigned char>(x+1, y) == 255) {
input.at<unsigned char>(x + 1, y) = count + 50;
if (jishu == 2000)
{
return;
}
fill_4(x+1, y, count, input, jishu);
}
if (input.at<unsigned char>(x, y+1) == 255) {
input.at<unsigned char>(x, y+1) = count + 50;
if (jishu == 2000)
{
return;
}
fill_4(x, y+1, count, input, jishu);
}
return;
}
int labelmark(Mat& input) {
// 用四邻域,八邻域斜角情况较复杂
/*
按行遍历元素:
如果值=0,则跳过;
如果值=255,则判断其上、右两个邻域是否
*/
int temp = 0;
int jishu = 0; // 记录递归次数,本函数在本机上,测试的最大可递归次数为2089,本函数中设置为2000,jishu==2000则结束递归。
int labelnum = 1;
for (int i = 1; i < input.rows-1; i++)
{
for (int j = 1; j < input.cols-1; j++)
{
// 这里是找到递归超限时添加的代码,没删,记录一下提醒自己
//cout << "这是for循环: " << i << ", " << j << endl;
//if (labelnum == 17 && input.at<unsigned char>(i, j) == 255) {
// // cout << "这是for循环: " << i << ", " << j << endl;
// //input.at<unsigned char>(i, j) = 0;
// cout << jishu << endl;
// jishu++;
// continue;
//}
if (input.at<unsigned char>(i, j) != 255 && input.at<unsigned char>(i, j) != 0) // 已经被标记过的
{
// 判断该像素四邻域是否存在值=255的,如果有,则将label变为当前像素值,再次进行递归
if (input.at<unsigned char>(i-1, j) == 255
|| input.at<unsigned char>(i, j - 1) == 255
|| input.at<unsigned char>(i + 1, j) == 255
|| input.at<unsigned char>(i, j + 1) == 255)
{
temp = input.at<unsigned char>(i, j)-50; // -50别忘了
fill_4(i, j, temp, input, jishu);
jishu = 0;
}
}
if (input.at<unsigned char>(i,j)==255)
{
input.at<unsigned char>(i, j) = labelnum + 50;
fill_4(i, j, labelnum, input, jishu);
labelnum+=10;
jishu = 0;
break;
}
}
}
return (labelnum - 1) / 10 + 1;
}
結果
とにかく、正解でした…
実験で使用した写真は論文に使用される場合があるので、当分公開できません(良いこと考えてくださいorz)
補充する
これは私が使用しているライブラリです。バージョン 2、バージョン 3 には **connectedComponents()** 接続ドメイン解決関数が付属しています。嫌いだ!