这次实用的函数是自己实现,这次使用方法:
使用近似一维Means方法寻找二值化阈值,该方法的大致步骤如下:
1. 一个初始化阈值T,可以自己设置或者根据随机方法生成。
2. 根据阈值图每个像素数据P(n,m)分为对象像素数据G1与背景像素数据G2。(n为
行,m为列)
3. G1的平均值是m1, G2的平均值是m2
4. 一个新的阈值T’ = (m1 + m2)/2
5. 回到第二步,用新的阈值继续分像素数据为对象与背景像素数据,继续2~4步,
直到计算出来的新阈值等于上一次阈值。
代码如下:
#include <cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int getAverage(Vector<int> array){
int s=array.size();
int ans=0;
for(int i=0;i<s;i++){
int t=array[i];
ans+=t;
}
return ans/s;
}
//获取阀值
int getthreshold(Mat src){
int fin=0;
int fir=127;
int h=src.rows;
int w=src.cols;
Vector<int> b;
Vector<int> s;
while(fir!=fin){
s.clear();
b.clear();
fin=fir;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
int t=src.at<uchar>(j,i);
if(t>fin){b.push_back(t);}
else s.push_back(t);
}
}
fir=(getAverage(b)+getAverage(s))/2;
//
}
return fin;
}
//获取二值图像
void getErZhiTuXiang(int th,Mat src){
int h=src.rows;
int w=src.cols;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
int t=src.at<uchar>(j,i);
if(t>th){src.at<uchar>(j,i)=255;}
else src.at<uchar>(j,i)=0;
}
}
}
int main( int argc, char** argv )
{
Mat image=imread("1.jpg");
Mat destImg;
cvtColor(image, destImg, CV_BGR2GRAY);
int th=getthreshold(destImg);
getErZhiTuXiang(th,destImg);
imshow("laplace",destImg);
imwrite("2.jpg",destImg);
waitKey(0);
return 0;
}
最后效果图: