This algorithm describes the reference link: http://blog.csdn.net/icvpr/article/details/10259577
two times scanning method:
(1) First scan:
Access current pixel B (x,y) if B (x,y) = = 1:
A, if the pixel value in the field of B (X,y) is 0, give B (x,y) a new label:
Label + = 1, B (x,y) = label;
b, if the domain of B (x,y) has pixel value > 1 pixel neighbors:
1 assigns the minimum value in the neighbors to B (x,y):
B (x,y) = min{neighbors}
(2) record the equivalence between the values (labels) in the neighbors, that is, the values (label) belong to the same connected region;
Labelset[i] = {label_m, ..., Label_n},labelset[i] All of the labels belong to the same connected region (note: There can be many ways to do this, as long as you can record the relationships between the labels that have an equality relationship)
(2) Second scan:
Access current pixel B (x,y) if B (x,y) > 1:
A, finding a minimum label value that is equivalent to the label = B (X,y), given to B (X,y);
After the scan is complete, pixels with the same label value in the image form the same connected region.
Algorithm Code:
Intuitively, the two-way method is faster than the Stack method, in fact the speed is only 1/5-1/10 of the stack method, the code is as follows:
Using the two-pass scan//Find all connected domains//simple methods, use the 1-0 matrix//column marking method to collect all connected domains//need to use the inverted index bool Cd2detectinpic::searchconby2way (const CV::MAT
& _binimg, float Valueforeb, float valueforeup, STD::VECTOR<STD::VECTOR<CV::P oint > > &foreareas) {
int vfore = 255;
int vback = 0;
Foreareas.resize (0);
Cv::mat _lableimg;
if (_binimg.channels () >1) {Cv::cvtcolor (_binimg,_lableimg,cv::color_bgr2gray);
else {_binimg.copyto (_lableimg);
//scan, get foreground and background points, mark//background Mark 0, foreground point marked as 1 #ifdef show_temp cv::imshow ("", _lableimg);//cv::waitkey (0);
#endif iplimage Imagelabel = _lableimg;
for (int i=0;i< imagelabel.height;++i) {char* PI = (char*) imagelabel.imagedata + i * IMAGELABEL.WIDTHSTEP;
for (int j=0;j<imagelabel.width;++j) {if (*pi >=valueforeb &&*pi <=valueforeup)//Avoid single value errors.
{*pi = Vfore;
else {*pi = Vback;
} ++pi;
}//The label image is traversed, looking for the connected domain//to mark Matrix, making modifications without modifying the identification matrix Cv::mat ImageMark (&imagelabel); Cv::mat imaGemarkre = Imagemark.clone ();
Use line scanning to separate merge//use Set set to represent equality #ifdef show_temp cv::imshow ("Imagemarkre", imagemarkre);//Cv::waitkey (1);
#endif std::stack<std::p air<int,int> > Neighborpixels;
Use another label matrix to record which connected domain the current point belongs to Cv::mat Conarealocmat = Cv::mat::zeros (_BINIMG.ROWS,_BINIMG.COLS,CV_8UC1);
Cv::bitwise_not (Conarealocmat,conarealocmat);
Iplimage imageconarealoc = Conarealocmat;
STD::VECTOR<STD::p AIR<CV::P oint,uchar> > Conareas (imagemark.cols);
STD::VECTOR<STD::VECTOR<CV::P oint> > Conpointsareas (0); Nth connected domain int counter =0;//is used to mark the nth connected domain int idx =0;//for hash index//Set repeating set///For last merge connected domain//std::vector<std::vector<int>
> Overlapvec (0);
Std::set<int,int> Overlapset; Std::multimap<int,int> overlapmap;//uses multivalued hashes//to divide the first row into connected domains {char* Plabel = (char*) Imagelabel.imagedata + 0* im
Agelabel.widthstep;
char* Ploc = (char*) Imageconarealoc.imagedata + 0* imageconarealoc.widthstep;
int lastl = *plabel;
if (Vfore = = Lastl) {++counter;
*ploc = counter;//count starting from 1, the index starts from 0//++idx;
std::p air<int,int> P (COUNTER,IDX);
Overlapmap.insert (P);//Insert Index} else {*ploc =-1;
int lastloc = *ploc;
++plabel;
++ploc; for (int n=1; n< imagemark.cols ++n) {if (Vfore = = *plabel)/If marked as connected domain, mark {if (*PLABEL==LASTL)/if and previous
Pixel Unicom, then marked as the previous tag {*ploc = Lastloc;
else {//If the previous is 0, add the tag symbol to ++counter the new tag;
*ploc = counter;
++idx;
std::p air<int,int> P (COUNTER,IDX);
Overlapmap.insert (P);//Insert index//std::cout<< idx << "_" <<counter<<std::endl;
} else {*ploc = -1;//if it encounters the nth point as the change point, the position labeled nth connected domain} LASTL = *plabel;
Lastloc = *ploc;
++ploc;
++plabel; To find connected fields for each row of the picture, you must traverse for (int m =1; m<imagemark.rows; ++m) {//assign to first pixel///previous line pointer char* Plabelfore =
(char*) Imagelabel.imagedata + (m-1) * IMAGELABEL.WIDTHSTEP; char* plocforE = (char*) Imageconarealoc.imagedata + (m-1) * IMAGECONAREALOC.WIDTHSTEP;
The pointer to this line char* Plabel = (char*) Imagelabel.imagedata + m* imagelabel.widthstep;
char* Ploc = (char*) Imageconarealoc.imagedata + m* imageconarealoc.widthstep;
Mark the first point, the line above is quasi int forel = *plabelfore;
int foreloc = *plocfore;
int lastl = *plabel;
if (*plabel = = Forel)/If equal to the value on the previous line, the connected field position is equal to the first value of the previous row {*ploc = *plocfore;
else {if (Vfore = = *plabel) {//If it is a connected domain, increase the markup symbol for the new tag ++counter;
*ploc = counter;
++idx;
std::p air<int,int> P (COUNTER,IDX);
Overlapmap.insert (P);//Insert index//std::cout<< idx << "_" <<counter<<std::endl;
else {*ploc =-1;
an int lastloc = *ploc; for (int n=0; n< imagemark.cols-1 ++n) {//Find the connected domain for each row Lastl = *plabel;//The last pixel's tag lastloc = *ploc;//The last pixel's connection
Pass-field position//to next pixel ++plabel;
++ploc;
++plabelfore;
++plocfore; Forel = *plabelfore;//on line ThisPosition pixel Value Foreloc = *plocfore;//The connected domain position of the last pixel if (vback = = *plabel)/If the current label is 0 {*ploc =-1; else {if (*plabel!= Forel)//If the current label is not equal to the previous row of pixels, the label {if (*plabel!= lastl) {//If the current label is not equal to the previous
The label of the Pixel is expressed as the beginning of the new connected domain, and the new set//If the connected domain, then the markup symbol is added to the ++counter;
*ploc = counter;
++idx;
std::p air<int,int> P (COUNTER,IDX);
Overlapmap.insert (P);//Insert index//std::cout<< idx << "_" <<counter<<std::endl;
else {//If the current label equals the label of the previous pixel, it is connected, the direct assignment *ploc = Lastloc;
} else {//if equal to the previous line of pixels, it is troublesome.
if (*plabel!= lastl)//if not equal to the previous pixel label, the tag {*ploc = Foreloc is assigned to the previous line;
else {if (Foreloc = = Lastloc)//If the previous and previous row equals {*ploc = Foreloc;
else {//If the previous and previous line is not equal///if equal to the previous pixel, you need to merge the set//tag the same set *ploc = Foreloc;
Merge hash table//lookup to the hash index where the value is located int idxf = (*overlapmap.find (foreloc)). int IDXFL = (*overlapmap.find (lastloc)). First;//map is looking for key instead of value int L1 = (*overlapmap.find (foreloc)). Second;
int L2 = (*overlapmap.find (lastloc)). Second;
if (L1!= L2)//If not in an index, you can delete {//Insert the current value into the index without increasing the IDX index//must first be deleted and then inserted in order to avoid accidentally deleting//removing the old key value pairs
Overlapmap.erase (IDXFL);//One parameter is key, is the wrong//int x = Overlapmap.erase (Lastloc);
Overlapmap.erase (IDXFL);
std::p air<int,int> P (idxf,lastloc);
std::p air<int,int> P (LASTLOC,L1);
Overlapmap.insert (P);
} else {}}}}} SYSTEMTIME sys;
Getlocaltime (&sys);
int milets = Sys.wsecond;int Milet = sys.wmilliseconds;
Direct lookup to position conpointsareas.resize (Overlapmap.size ());
Iplimage imageconarea= Imageconarealoc;
for (int i=0;i< imageconarea.height;++i) {char* PI = (char*) imageconarea.imagedata + i * IMAGECONAREA.WIDTHSTEP; for (int j=0;j<imagECONAREA.WIDTH;++J) {if (*pi >0) {cv::P oint P (j,i);
int idx = (*overlapmap.find ((int) *pi)). Second-1;
Conpointsareas[idx].push_back (P);
} ++pi;
an int validvec = 0;
Foreareas.resize (Validvec);
for (int i=0;i< conpointsareas.size (); ++i) {if (Conpointsareas[i].size () >0) {++validvec;
Foreareas.push_back (Conpointsareas[i]);
} getlocaltime (&sys);
int MileT2 = Sys.wmilliseconds;
int detat = Milet2-milet;
std::cout<< Std::endl;
std::cout<< "The Copyvec Time is:" << detat<< "MS ..." << Std::endl;
std::cout<< Std::endl;
Conpointsareas.resize (0);
return true; }