【影象處理】利用種子填充法對二值影象進行連通域標記-計算目標中心位置方法2
種子填充法原理
- 大致演算法如下:
- 設二值化影象A中,畫素值為255的點是前景,為0的點是背景。A(x, y)為座標(x, y)處的畫素值,遍歷影象的每個畫素:
- 1、 如果畫素值不等於255,則繼續訪問下一個元素。
- 2、 如果畫素值為A(x, y) = 255,則新建一個新的label,當前值A(x, y) = label,並且
- a. 檢查其4個鄰域,如果有屬於前景的畫素也給它賦予label值,並將它的座標壓棧。
-
b. 彈出棧頂座標,重複a的過程,知道堆疊為空。
此時,便找到了一個連通區域,該區域內的畫素值被標記為label。
3、 重複1、2的過程,檢測出所有的區域。
廢話少說,上程式碼!
實現程式
該程式基於OpenCV2.4.9 和VS2010平臺:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
using namespace cv;
typedef struct _Feather
{
int label; // 連通域的label值
int area; // 連通域的面積
Rect boundingbox; // 連通域的外接矩形框
} Feather;
/*
Input:
src: 待檢測連通域的二值化影象
Output:
dst: 標記後的影象
featherList: 連通域特徵的清單
return:
連通域數量。
*/
int bwLabel(Mat & src, Mat & dst, vector<Feather> & featherList)
{
int rows = src.rows;
int cols = src.cols;
int labelValue = 0;
Point seed, neighbor;
stack <Point> pointStack; // 堆疊
int area = 0; // 用於計算連通域的面積
int leftBoundary = 0; // 連通域的左邊界,即外接最小矩形的左邊框,橫座標值,依此類推
int rightBoundary = 0;
int topBoundary = 0;
int bottomBoundary = 0;
Rect box; // 外接矩形框
Feather feather;
featherList.clear(); // 清除陣列
dst.release();
dst = src.clone();
for( int i = 0; i < rows; i++)
{
uchar *pRow = dst.ptr<uchar>(i);
for( int j = 0; j < cols; j++)
{
if(pRow[j] == 255)
{
area = 0;
labelValue++; // labelValue最大為254,最小為1.
seed = Point(j, i); // Point(橫座標,縱座標)
dst.at<uchar>(seed) = labelValue;
pointStack.push(seed);
area++;
leftBoundary = seed.x;
rightBoundary = seed.x;
topBoundary = seed.y;
bottomBoundary = seed.y;
while(!pointStack.empty())
{
neighbor = Point(seed.x+1, seed.y);
if((seed.x != (cols-1)) && (dst.at<uchar>(neighbor) == 255))
{
dst.at<uchar>(neighbor) = labelValue;
pointStack.push(neighbor);
area++;
if(rightBoundary < neighbor.x)
rightBoundary = neighbor.x;
}
neighbor = Point(seed.x, seed.y+1);
if((seed.y != (rows-1)) && (dst.at<uchar>(neighbor) == 255))
{
dst.at<uchar>(neighbor) = labelValue;
pointStack.push(neighbor);
area++;
if(bottomBoundary < neighbor.y)
bottomBoundary = neighbor.y;
}
neighbor = Point(seed.x-1, seed.y);
if((seed.x != 0) && (dst.at<uchar>(neighbor) == 255))
{
dst.at<uchar>(neighbor) = labelValue;
pointStack.push(neighbor);
area++;
if(leftBoundary > neighbor.x)
leftBoundary = neighbor.x;
}
neighbor = Point(seed.x, seed.y-1);
if((seed.y != 0) && (dst.at<uchar>(neighbor) == 255))
{
dst.at<uchar>(neighbor) = labelValue;
pointStack.push(neighbor);
area++;
if(topBoundary > neighbor.y)
topBoundary = neighbor.y;
}
seed = pointStack.top();
pointStack.pop();
}
box = Rect(leftBoundary, topBoundary, rightBoundary-leftBoundary, bottomBoundary-topBoundary);
rectangle(src, box, 255);
feather.area = area;
feather.boundingbox = box;
feather.label = labelValue;
featherList.push_back(feather);
}
}
}
return labelValue;
}
int main(int argc, char *argv[])
{
Mat src(imread("shape.jpg", 0));
if(src.empty())
exit(-1);
threshold(src, src, 127, 255, THRESH_BINARY); // 二值化影象
vector<Feather> featherList; // 存放連通域特徵
Mat dst;
cout << "連通域數量: " << bwLabel(src, dst, featherList) << endl;
// 為了方便觀察,可以將label“放大”
for( int i = 0; i < dst.rows; i++)
{
uchar *p = dst.ptr<uchar>(i);
for( int j = 0; j < dst.cols; j++)
{
p[j] = 30*p[j];
}
}
cout << "標號" << "\t" << "面積" << endl;
for(vector<Feather>::iterator it = featherList.begin(); it < featherList.end(); it++)
{
cout << it->label << "\t" << it->area << endl;
rectangle(dst, it->boundingbox, 255);
}
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
執行結果:
原圖:
檢測結果:
特徵清單:
相關推薦
【影象處理】利用種子填充法對二值影象進行連通域標記-計算目標中心位置方法2
種子填充法原理 大致演算法如下: 設二值化影象A中,畫素值為255的點是前景,為0的點是背景。A(x, y)為座標(x, y)處的畫素值,遍歷影象的每個畫素: 1、 如果畫素值不等於255,則繼續訪問下一個元素。 2、 如果畫素值為A(x, y) = 255,則新建一
實現基於C語言的二值圖像連通域標記算法
ror mem main hair return pop incr one get 實現基於C語言的二值圖像連通域標記算法 1 #include <stdio.h> 2 #include <stdarg.h> 3 #include &l
【影象處理】openCV光流法追蹤運動物體
openCV光流法追蹤運動物體 email:[email protected] 一、光流簡介 光流的概念是Gibson在1950年首先提出來的。它是空間運動物體在觀察成像平面上的畫素運動的瞬時速度,是利用影象序列中畫素在時間域上的變化以及相鄰幀之
【影象處理】FPGA verilog實現16位RGB的影象的灰度轉換
專案:FPGA verilog實現16位RGB的影象的轉換為8位寬的灰度圖。 專案需要的模組:呼叫一個RAM,16*22500,灰度處理模組和VGA800X600模組。 本次用到的FPGA是spartan6 X16。因為資源少,所以先嚐試的做點簡單的影
【數字影象處理】C++讀取、旋轉和儲存bmp影象檔案程式設計實現
通過我這些天用C++讀寫bmp影象的經歷,摸索再摸索,終於對bmp檔案的結構、操作有了一定的瞭解,下面就大概介紹bmp圖片純C++的讀取、旋轉和儲存的實現過程。 有幾點需要注意的是: 在讀取bmp圖片的時候,一定要注意記憶體對齊的問題,譬如檔案頭,否則無法讀取出正確結果。
利用PIL.ImageOps.invert實現二值影象黑白反轉
利用PIL.ImageOps.invert實現二值影象黑白反轉 import PIL.ImageOps from PIL import Image img = Image.open('D:\\Desktop\\計算機視覺\\image\\0.png') img =
【計算機視覺】基於Shading Model(對光照變化一定不變性)的運動目標檢測演算法
光照模型(Shading Model)在很多論文中得到了廣泛的應用,如robust and illumination invariant change detection based on linear dependence for surveillance applic
使用Matlab對二值影象進行輪廓提取
對圖1的檢測效果如圖3所示: 圖3 edge檢測結果 參考資料 [1]輪廓提取 ===================================================================================
使用迭代法對二叉樹進行前序遍歷——Leetcode系列(七)
Given a binary tree, return the preorder traversal of its nodes' values. For example: Given binary
【資訊科技】【2010.12】利用影象處理實現實時事故檢測系統的有效步驟
本文為印度安娜大學(作者:LOGESHVASU)的電子與通訊工程學士論文,共145頁。 隨著現代CPU處理器運算能力的提高,許多複雜的實時應用已經成為可能,並在世界範圍內的各個領域得以實現。其中廣泛的實時應用之一是視訊監控系統。視訊監控系統已被用於安全監控、異
【OpenCV】8鄰域種子填充法剔除短連通域的高效演算法
//本文件參考種子填充演算法描述及C++程式碼實現(https://www.bbsmax.com/A/amd0AVWzge/)講解的原理,實現快速種子填充演算法,執行效果高。 //具體功能如下:依次掃描每個畫素,檢測8領域,尋找連通域,刪掉面積小於閾值的。 #define IMG_MARGIN
【程式語言】利用CImage類對影象畫素的處理(影象二值化)
最近做的課程作業需要用到CImage函式處理影象,其中涉及到讀取影象以及對影象畫素進行操作,在這裡記錄一下自己的理解。 首先是CImage類的定義和讀取圖片 CImage srcImage; CImage dstImage; CString path = "
【圖像處理】openCV光流法追蹤運動物體
num blank ndis water 不同 h+ width 相關性 ida openCV光流法追蹤運動物體 email:[email protected]/* */ 一、光流簡單介紹 摘自:zouxy09 光流的概念是G
【MySQL】【復制】利用slave_exec_mode處理復制過程中出現的1062與1032錯誤
cati 事務 thead 組成 .cn 推薦 ren 報錯 引入 背景: ? 今天張師兄在群裏問了主從之間出現1032錯誤後,使用pt-slave-restart跳過後又出現了1062錯誤,該如何快速處理。 問題解析: ? 1032錯誤:主庫傳遞過來的binlog
【opencv入門】漫水填充算法(Floodfill)
部件 tro 分享圖片 函數的原型 過程 輪詢 output 輸入 通用 一、引言 · 漫水填充的定義 漫水填充法是一種用特定的顏色填充聯通區域,通過設置可連通像素的上下限以及連通方式來達到不同的填充效果的方法。漫水填充經常被用來標記或分離圖像的一部分以便對其進行進一步
【C語言】利用選擇法進行從小到大排序
選擇法思路: 取其中的最大值與最後一個數進行交換 假設一共有6個數組,我們用選擇法進行從小到大的排序; 6,5,4,2,3,1 第一次: 【6,5,4,2,3,1】->> 【1,5,4,2,3,6】 第二次:【1,5,4,2,3】,6 ->>【1
【C語言】 利用篩選法求100以內的素數
演算法思路: 原理很簡單,就是當i是質(素)數的時候,i的所有的倍數必然是合數。如果i已經被判斷不是質數了,那麼再找到i後面的質數來把這個質數的倍數篩掉。 程式碼如下: //C語言 篩選法求100以內的素數 //原理很簡單,就是當i是質(素)數的時候,i的所有的倍數必然是合數。如果i已經
【影象處理】 增加程式速度的方法
1. stack(棧) heap(堆) 和全域性區 測試BGR轉YUV 的表在stack 和 heap 2. 查詢表 部分查詢表 和3D查詢表 速度比較 3. 查詢表放在堆上和棧上的速度比較 4.
【影象處理】工業相機原理詳述 (轉載)
轉自: https://blog.csdn.net/HelloZEX/article/details/80905095 工業相機是機器視覺系統中的一個關鍵元件,其最本質的功能就是將光訊號轉變成有序的電訊號。選擇合適的相機也是機器視覺系統設計中的重要環節,相機的選擇不僅直接決定所採集到的影象
【影象處理】Lightroom Classic CC 2019 for Mac中文破解版
Lightroom Classic CC 2019 for Mac中文破解版是目前最強大的影象處理軟體之一,簡稱Lr CC 2019破解版,使用lightroom mac 破解版可以讓您獲得最佳的攝影效果所提供的圖片整理編輯工具,提高照片的色彩、刪除瑕疵、伸展畫面等等,可以為您的照片錦上添花。新版L