图像分割-分割和合并(四叉树)
本文关键字:四叉树 合并 分割 图像分割 | 更新日期: 2023-09-27 18:05:22
是否有图像分割的分割和合并方法的实现?如有任何建议,不胜感激。
什么是分段?
分割是指将你的图像分割成几个相连的区域。基本上,您可以使用两种区域定义进行分割:您可以将区域定义为一组连接的相似像素,或者一组由不连续点(边缘)包围的连接像素。分割和合并使用第一种方法。
从数学上讲:如果你的整个图像是由一组像素(称为R)表示的,那么你会想得到像
这样的子集- 分割完成,因此所有子区域之和为整个R。所有区域的并集为R1 U R2 U…U Rn = R
- Ri已连接。
- 区域是不同的。我R <子>子>帽;j R <子>子> =空;考虑到i≠j
- 区域具有类似的属性。这可以用一个称为均匀性准则(P)的函数来表示。对于给定区域的成员,它应该为TRUE,对于所有其他区域,它应该为FALSE。
- 邻居区域不能合并。对于所有区域P(Ri U Rj)=FALSE,给定i≠j.
拆分和合并算法是关于什么的?
所以首先,我们必须选择一个齐次准则。均匀性标准可以是全局的(取决于整个区域)或局部的(取决于区域的一个小窗口,如果对所有窗口都成立,那么对区域也是成立的)。一个简单的例子是,与平均值的偏差应该小于阈值。我原则;p <子>子> isin; R <子>子>:|我<子>子> & # 956;|勒;f * & # 963;。
拆分和合并算法有两个阶段:拆分和合并阶段。在分割阶段,我们递归地将区域分成四个子区域(从整个图像作为一个区域开始),直到所有子区域都满足我们的均匀性标准。很容易看出分割的1-4个条件都满足了。为了满足5条件,我们继续进行合并步骤。
在合并步骤中,我们检查每两个相邻区域的p (Ri U Rj)=TRUE,并合并这两个区域。我们重复这个步骤,直到不再需要更改为止。现在我们满足了所有条件,我们将图像分割成子区域。
下面是分割和合并算法的伪代码:
- Init:我们只有一个大的区域(整个图像)。
- 分裂:如果P(Ri)=TRUE继续下一步。否则将Ri细分为4个子区域,并对其执行步骤2。
- 合并:如果Ri和Rj相邻且P(Ri U Rj) = TRUE,则合并两个区域,然后重复步骤3。如果没有这样的区域,我们就完了。
这是我的实现。我不是一个c++/opencv大师,所以如果有人找到一些方法来优化这个脚本添加评论请!
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
using namespace cv;
using namespace std;
Mat img;
Size size;
struct region {
// tree data structure
vector<region> childs;
bool validity; // TODO: have a method for clear the data structure and remove regions with false validity
// tree for split&merge procedure
Rect roi;
Mat m;
Scalar label;
Mat mask; // for debug. don't use in real cases because it is computationally too heavy.
};
//----------------------------------------------------------------------------------------------------------------------- merging
bool mergeTwoRegion(region& parent, const Mat& src, region& r1, region& r2, bool (*predicate)(const Mat&)) {
if(r1.childs.size()==0 && r2.childs.size()==0) {
Rect roi1 = r1.roi;
Rect roi2 = r2.roi;
Rect roi12 = roi1 | roi2;
if(predicate( src(roi12) )) {
r1.roi = roi12;
// recompute mask
r1.mask = Mat::zeros(size, CV_8U);
rectangle(r1.mask, r1.roi, 1, CV_FILLED);
r2.validity = false;
return true;
}
}
return false;
}
void merge(const Mat& src, region& r, bool (*predicate)(const Mat&)) {
// check for adjiacent regions. if predicate is true, then merge.
// the problem is to check for adjiacent regions.. one way can be:
// check merging for rows. if neither rows can be merged.. check for cols.
bool row1=false, row2=false, col1=false, col2=false;
if(r.childs.size()<1) return;
// try with the row
row1 = mergeTwoRegion(r, src, r.childs[0], r.childs[1], predicate);
row2 = mergeTwoRegion(r, src, r.childs[2], r.childs[3], predicate);
if( !(row1 | row2) ) {
// try with column
col1 = mergeTwoRegion(r, src, r.childs[0], r.childs[2], predicate);
col2 = mergeTwoRegion(r, src, r.childs[1], r.childs[3], predicate);
}
for(int i=0; i<r.childs.size(); i++) {
if(r.childs[i].childs.size()>0)
merge(src, r.childs[i], predicate);
}
}
//----------------------------------------------------------------------------------------------------------------------- quadtree splitting
region split(const Mat& src, Rect roi, bool (*predicate)(const Mat&)) {
vector<region> childs;
region r;
r.roi = roi;
r.m = src;
r.mask = Mat::zeros(size, CV_8U);
rectangle(r.mask, r.roi, 1, CV_FILLED);
r.validity = true;
bool b = predicate(src);
if(b) {
Scalar mean, s;
meanStdDev(src, mean, s);
r.label = mean;
} else {
int w = src.cols/2;
int h = src.rows/2;
region r1 = split(src(Rect(0,0, w,h)), Rect(roi.x, roi.y, w,h), predicate);
region r2 = split(src(Rect(w,0, w,h)), Rect(roi.x+w, roi.y, w,h), predicate);
region r3 = split(src(Rect(0,h, w,h)), Rect(roi.x, roi.y+h, w,h), predicate);
region r4 = split(src(Rect(w,h, w,h)), Rect(roi.x+w, roi.y+h, w,h), predicate);
r.childs.push_back( r1 );
r.childs.push_back( r2 );
r.childs.push_back( r3 );
r.childs.push_back( r4 );
}
//merge(img, r, predicate);
return r;
}
//----------------------------------------------------------------------------------------------------------------------- tree traversing utility
void print_region(region r) {
if(r.validity==true && r.childs.size()==0) {
cout << r.mask << " at " << r.roi.x << "-" << r.roi.y << endl;
cout << r.childs.size() << endl;
cout << "---" << endl;
}
for(int i=0; i<r.childs.size(); i++) {
print_region(r.childs[i]);
}
}
void draw_rect(Mat& imgRect, region r) {
if(r.validity==true && r.childs.size()==0)
rectangle(imgRect, r.roi, 50, .1);
for(int i=0; i<r.childs.size(); i++) {
draw_rect(imgRect, r.childs[i]);
}
}
void draw_region(Mat& img, region r) {
if(r.validity==true && r.childs.size()==0)
rectangle(img, r.roi, r.label, CV_FILLED);
for(int i=0; i<r.childs.size(); i++) {
draw_region(img, r.childs[i]);
}
}
//----------------------------------------------------------------------------------------------------------------------- split&merge test predicates
bool predicateStdZero(const Mat& src) {
Scalar stddev, mean;
meanStdDev(src, mean, stddev);
return stddev[0]==0;
}
bool predicateStd5(const Mat& src) {
Scalar stddev, mean;
meanStdDev(src, mean, stddev);
return (stddev[0]<=5.8) || (src.rows*src.cols<=25);
}
//----------------------------------------------------------------------------------------------------------------------- main
int main( int /*argc*/, char** /*argv*/ )
{
img = (Mat_<uchar>(4,4) << 0,0,1,1,
1,1,1,1,
3,3,3,3,
3,4,4,3);
cout << img << endl;
size = img.size();
region r;
r = split(img, Rect(0,0,img.cols,img.rows), &predicateStdZero);
merge(img, r, &predicateStdZero);
cout << "------- print" << endl;
print_region(r);
cout << "-----------------------" << endl;
img = imread("lena.jpg", 0);
// round (down) to the nearest power of 2 .. quadtree dimension is a pow of 2.
int exponent = log(min(img.cols, img.rows)) / log (2);
int s = pow(2.0, (double)exponent);
Rect square = Rect(0,0, s,s);
img = img(square).clone();
namedWindow("original", CV_WINDOW_AUTOSIZE);
imshow( "original", img );
cout << "now try to split.." << endl;
r = split(img, Rect(0,0,img.cols,img.rows), predicateStd5);
cout << "splitted" << endl;
Mat imgRect = img.clone();
draw_rect(imgRect, r);
namedWindow("split", CV_WINDOW_AUTOSIZE);
imshow( "split", imgRect );
imwrite("split.jpg", imgRect);
merge(img, r, &predicateStd5);
Mat imgMerge = img.clone();
draw_rect(imgMerge, r);
namedWindow("merge", CV_WINDOW_AUTOSIZE);
imshow( "merge", imgMerge );
imwrite( "merge.jpg", imgMerge );
Mat imgSegmented = img.clone();
draw_region(imgSegmented, r);
namedWindow("segmented", CV_WINDOW_AUTOSIZE);
imshow( "segmented", imgSegmented );
imwrite( "segmented.jpg", imgSegmented );
while( true )
{
char c = (char)waitKey(10);
if( c == 27 ) { break; }
}
return 0;
}