在这里插入代//* 函数名称: cvOtsu2D()
//* 函数参数: CvMat* pGrayMat : 灰度图形相对应的矩阵
//* 返回值 : int nThreshold
//* 函数说明 : 实现灰度图的二值化分割——最大类间方差法(二维Otsu算法/大津算法)
//* 备注:在构建二维直方图的时候,采用灰度点的3 * 3邻域均值
int cvOtsu2D(CvMat *pGrayMat)
{
double dHistogram[256][256]; //建立二维灰度直方图
double dTrMatrix = 0.0; //离散矩阵的迹
int height = pGrayMat->rows;
int width = pGrayMat->cols;
int N = height*width; //总像素数
int i, j;
for (i = 0; i < 256; i++)
{
for (j = 0; j < 256; j++)
dHistogram[i][j] = 0.0; //初始化变量
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
unsigned char nData1 = (unsigned char)cvGetReal2D(pGrayMat, i, j);//当前的灰度值
unsigned char nData2 = 0;
int nData3 = 0;//注意9个值相加可能超过一个字节
for (int m = i - 1; m <= i + 1; m++)
{
for (int n = j - 1; n <= j + 1; n++)
{
if ((m >= 0) && (m < height) && (n >= 0) && (n < width))
nData3 += (unsigned char)cvGetReal2D(pGrayMat, m, n); //当前的灰度值
}
}
nData2 = (unsigned char)(nData3 / 9); //对于越界的索引值进行补零,邻域均值
dHistogram[nData1][nData2]++;
}
}
for (i = 0; i < 256; i++)
for (j = 0; j < 256; j++)
dHistogram[i][j] /= N; //得到归一化的概率分布
double Pai = 0.0; //目标区均值矢量i分量
double Paj = 0.0; //目标区均值矢量j分量
double Pbi = 0.0; //背景区均值矢量i分量
double Pbj = 0.0; //背景区均值矢量j分量
double Pti = 0.0; //全局均值矢量i分量
double Ptj = 0.0; //全局均值矢量j分量
double W0 = 0.0; //目标区的联合概率密度
double W1 = 0.0; //背景区的联合概率密度
double dData1 = 0.0;
double dData2 = 0.0;
double dData3 = 0.0;
double dData4 = 0.0; //中间变量
int nThreshold_s = 0;
int nThreshold_t = 0;
double temp = 0.0; //寻求最大值
for (i = 0; i < 256; i++)
{
for (j = 0; j < 256; j++)
{
Pti += i*dHistogram[i][j];
Ptj += j*dHistogram[i][j];
}
}
for (i = 0; i < 256; i++)
{
for (j = 0; j < 256; j++)
{
W0 += dHistogram[i][j];
dData1 += i*dHistogram[i][j];
dData2 += j*dHistogram[i][j];
W1 = 1 - W0;
dData3 = Pti - dData1;
dData4 = Ptj - dData2;
Pai = dData1 / W0;
Paj = dData2 / W0;
Pbi = dData3 / W1;
Pbj = dData4 / W1; // 得到两个均值向量,用4个分量表示
dTrMatrix = ((W0 * Pti - dData1) * (W0 * Pti - dData1) + (W0 * Ptj - dData2) * (W0 * Ptj - dData2)) / (W0 * W1);
if (dTrMatrix > temp)
{
temp = dTrMatrix;
nThreshold_s = i;
nThreshold_t = j;
}
}
}
int nThreshold = (nThreshold_s + nThreshold_t) / 2;//返回阈值,有多种形式,可以单独某一个,也可 //是两者的均值
return nThreshold;
}
//* 函数名称:
//* 函数参数: 需要处理的图像的数量:n
//* 返回值 : 无返回值,将处理之后的图片保存起来
//* 函数说明 : 实现采集的原始图像进行中值滤波后二值化并且得到阈值
//* 备注:中值滤波的5 * 5邻域,在膨胀算法使用9 * 9邻域
void Pict_Proce(int n)
{
for (int i = 0; i < n; i++)
{
//打开图片
char srcname[100];
sprintf(srcname, "C:\\Users\\Administrator\\Desktop\\USE__DH\\picture\\焊缝采集原始bmp图片\\%d.bmp", i);
Mat src1 = imread(srcname,-1);
if (src1.empty())
cout << "第" << i << "图片打开失败" << endl;
else
cout << "第" << i << "图片打开成功" << endl;
//畸变校正
Mat src = Picture_jiaozheng(src1);
//中值滤波
Mat dst1;
medianBlur(src, dst1,9);
//保存滤波后的灰度图
char save_med_name[100];
sprintf(save_med_name, "C:\\Users\\Administrator\\Desktop\\USE__DH\\picture\\焊缝图像处理结果\\%d.bmp", i);
imwrite(save_med_name, dst1);
cout << "第" << i << "图片处理完成" << endl;
//迭代法进行图像二值化
//读取图片
char dst2_name[100];
sprintf(dst2_name, "C:\\Users\\Administrator\\Desktop\\USE__DH\\picture\\焊缝图像处理结果\\%d.bmp", i);
IplImage *img = cvLoadImage(dst2_name, 0);//加载图片
CvMat *imgMat = cvCreateMat(img->height, img->width, CV_8UC1);//创建矩阵,其type为CV_8UC1
cvConvert(img, imgMat);//将图像转换成矩阵形式
int t = cvOtsu2D(imgMat);//求二维阈值分割的阈值
cout << "第" << i << "幅阈值为" << t << endl;
cvThreshold(img, img, t, 255, CV_THRESH_BINARY);//用求得的阈值分割图像
cv::Mat dst2 = cv::cvarrToMat(img);
//二值化图像膨胀
Mat dst;
Mat element = getStructuringElement(MORPH_ELLIPSE,Size(9,9));
dilate(dst2,dst,element);
//保存最终的图片
char result_name[100];
sprintf(result_name, "C:\\Users\\Administrator\\Desktop\\USE__DH\\picture\\焊缝图像处理结果\\result_%d.bmp", i);
imwrite(result_name, dst);
cout << "第" << i << "图片二值化完成" << endl;
}
}
码片
中值滤波之后,将焊缝图像进行二值化并且获得阈值,效果如图。在焊接机器人自动焊接的图像处理中效果很好。