作者:鸭大楚春秋 老师:曾老师
对图像二值化有全局阈值化和局部二值化。全局二值化比较典型的就是大津法
全局二值化对光照非常敏感,局部二值化好一些
#include <opencv.hpp>
#include <iostream>
#include <time.h>
#include <opencv2/imgproc/types_c.h>
#include <sstream>
using namespace std;
using namespace cv;
int main()
{
String imgLoad = "4.jpg";
Mat image = imread(imgLoad);
cvtColor(image, image, CV_RGB2GRAY);
//局部二值化
int blockSize = 25;
int constValue = 10;
cv::Mat local;
//cv::threshold(image, local, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
cv::adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, blockSize, constValue);
//基于形态学去噪:腐蚀和膨胀
int element_size = 1;//3
//创建结构元
int s = element_size * 2 + 1;//必须是奇数
Mat structureElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
Mat dst;
//两次闭运算,先膨胀后腐蚀
dilate(local, dst, structureElement, Point(-1, -1), 1);
erode(dst, dst, structureElement);
dilate(dst, dst, structureElement, Point(-1, -1), 1);
erode(dst, dst, structureElement);
//两次开运算,先腐蚀后膨胀
erode(dst, dst, structureElement);
dilate(dst, dst, structureElement, Point(-1, -1), 1);
erode(dst, dst, structureElement);
dilate(dst, dst, structureElement, Point(-1, -1), 1);
namedWindow("去噪后图像", 0);
imshow("去噪后图像", dst);
cv::waitKey(0);
//String imgWrite = "result3.jpg";
//imwrite(imgWrite, dst);
}
原图片
4.jpg
局部二值化
result4.jpg
全局二值化
result4_1.jpg
二值化以后可以发现:有很多“椒盐噪声”
可以使用形态学的方法去除
两个基本操作:腐蚀和膨胀
erode.png
组合运算:开运算和闭运算
open.png
经过尝试,进行闭运算,再进行开运算效果更好
同时开运算闭运算的次数影响不大,但是结构元大小影响很大,建议是3(最小)。
先开运算后闭运算
result1.jpg
先闭运算再开运算:可惜容易误伤边界
result1.jpg
这是我实现的大津法
输入图像,返回全局阈值
{
int th;//最佳分割阈值
const int GrayScale = 256;//图像的灰度级数
int pixCount[GrayScale] = { 0 };//每个灰度值所占像素个数
int pixSum = src.cols*src.rows;//图像总像素点
double pixPro[GrayScale] = { 0 };
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
pixCount[src.at<uchar>(i, j)]++;//统计每个灰度级的像素的个数
}
}
for (int i = 0; i < GrayScale; i++)
{
pixPro[i] = pixCount[i] * 1.0 / pixSum;//计算每个灰度级的像素数目占整幅图像的比例
}
//遍历所有从0到255灰度级的阈值T(分割),比较哪一个的类间方差最大
double w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp;
double deltaMax = 0;
for (int i = 0; i < GrayScale; i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;
for (int j = 0; j < GrayScale; j++)
{
//前景
if (j <= i)
{
w0 += pixPro[j];
u0tmp += j * pixPro[j];
}
else//背景
{
w1 += pixPro[j];
u1tmp += j * pixPro[j];
}
}
u0 = u0tmp / w0;
u1 = u1tmp / w1;
deltaTmp = w0 * w1*pow((u0 - u1), 2);
if (deltaTmp> deltaMax)
{
deltaMax = deltaTmp;
th = i;
}
}
return th;
}
我的原本思路是按照局部二值化后的结果,进行倾斜校正。
根据我阅读的论文,应该采用顶点链编码的方法。但是顶点链编码难度有点大,我先完成一个可以运行的系统,采用比如霍夫变换等比较成熟的方法,然后再试试顶点链编码的效果。
网友评论