形态学操作应用-提取水平与垂直线
原理方法:
图像形态学操作时候,可以通过自定义的结构元素实现结构元素
对输入图像一些对象敏感、另外一些对象不敏感,这样就会让敏
感的对象改变而不敏感的对象保留输出。通过使用两个最基本的
形态学操作 – 膨胀与腐蚀,使用不同的结构元素实现对输入图像
的操作、得到想要的结果。
- 膨胀,输出的像素值是结构元素覆盖下输入图像的最大像素值
- 腐蚀,输出的像素值是结构元素覆盖下输入图像的最小像素值
代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("C:/Users/Administrator/Pictures/hello.png");
if (src.empty()) {
printf("不能加载图像");
return -1;
}
namedWindow("创建成功", CV_WINDOW_AUTOSIZE);
imshow("创建成功", src);
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
namedWindow("gray image", 1);
imshow("gray image", gray);
Mat binImg;
adaptiveThreshold(~gray, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
imshow("binary image", binImg);
waitKey(0);
return 0;
}
图1-1 原图像灰度图像与二值图像
其中代码参数:
Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));//水平结构元素
Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.rows / 16), Point(-1, -1));//竖直结构元素
Mat dst;
Mat temp;
erode(binImg, temp, hline);
dilate(temp, dst, hline);
bitwise_not(dst, dst);
imshow("Final Result", dst);
开操作后提取水平线:
图1-2 提取水平线
开操作后提取竖直线:
图1-3 提取竖直线
开操作也可以用这一句:
morphologyEx(binImg, dst, CV_MOP_OPEN, vline);
bitwise_not(dst, dst);这一句是颜色反转。
应用:提取验证码
图1-4 效果图
注意:图片名称最好不要是中文。
图像金字塔
上采样和降采样
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("C:/Users/Administrator/Pictures/20160711084909.jpg");
if (src.empty()) {
printf("不能加载图像");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat dst, dstdown;
pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
imshow("output image", dst);
pyrDown(src, dstdown, Size(src.cols / 2, src.rows / 2));
imshow("output2 image", dstdown);
waitKey(0);
return 0;
}
图1-5 上采样和降采样
高斯不同(DOG)
Difference Of Gaussian
Mat gray, g1, g2, dogImg;
cvtColor(src, gray, CV_BGR2GRAY);
GaussianBlur(gray, g1, Size(3, 3), 0, 0);
GaussianBlur(g1, g2, Size(3, 3), 0, 0);
subtract(g1, g2, dogImg, Mat());
imshow("dogImg", dogImg);
waitKey(0);
return 0;
}
此时可以看到一点微弱的轮廓,是因为图像变化后不明显。
图1-6 不明显的高斯不同图
此时加入
normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);
将图像在0-255的地方归一化,如图所示:
图1-7 归一化后的高斯不同图
完整代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main(int argc, char** argv) {
Mat src = imread("C:/Users/Administrator/Pictures/20160711084909.jpg");
if (src.empty()) {
printf("不能加载图像");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat dst, dstdown;
//上采样
pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
imshow("output image", dst);
//降采用
pyrDown(src, dstdown, Size(src.cols / 2, src.rows / 2));
imshow("output2 image", dstdown);
//DOG
Mat gray, g1, g2, dogImg;
cvtColor(src, gray, CV_BGR2GRAY);
GaussianBlur(gray, g1, Size(5, 5), 0, 0);
GaussianBlur(g1, g2, Size(5, 5), 0, 0);
subtract(g1, g2, dogImg, Mat());
//归一化显示
normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);
imshow("dogImg", dogImg);
waitKey(0);
return 0;
}
基本阈值操作
分割类型:
超过阈值的就和阈值取相等。
小于阈值的取0.
大于阈值取0.
寻找阈值的方法:
- 二值化阈值
代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int threshold_value = 127;
int threshold_max = 255;
Mat src, dst;
const char* output_title = "binary image";
void Threshold_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/Administrator/Pictures/20160711084909.jpg");
if (src.empty()) {
printf("不能加载图像");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow("input image", src);
createTrackbar("Threshold Value", output_title, &threshold_value, threshold_max, Threshold_Demo);
Threshold_Demo(0, 0);
waitKey(0);
return 0;
}
void Threshold_Demo(int, void*) {
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
threshold(gray, dst, threshold_value, threshold_max, THRESH_BINARY);//二值化阈值
imshow(output_title, dst);
}
图1-8 二值化阈值
注意,如果需要生成动态调节结构元素的控制条,必须要先创建namedwindow这个窗口,如果直接imshow是不会生成控制条的。
- 反向二值化阈值
threshold(gray, dst, threshold_value, threshold_max, THRESH_BINARY_INV);
图1-9 反向二值化阈值
这五种操作可以新建一个trackbar统一起来,用type_value来代表五种不同的操作。效果如下:
图1-10 五种操作集合
代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int threshold_value = 127;
int threshold_max = 255;
int type_value = 2;
int type_max = 4;
Mat src, dst;
const char* output_title = "binary image";
void Threshold_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/Administrator/Pictures/20160711084909.jpg");
if (src.empty()) {
printf("不能加载图像");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow("input image", src);
createTrackbar("Threshold Value", output_title, &threshold_value, threshold_max, Threshold_Demo);
createTrackbar("Type Value", output_title, &type_value, type_max, Threshold_Demo);//这个trackbar可以改变type_value的值
Threshold_Demo(0, 0);
waitKey(0);
return 0;
}
void Threshold_Demo(int, void*) {
Mat gray;
cvtColor(src, gray, CV_BGR2GRAY);
//threshold(gray, dst, threshold_value, threshold_max, THRESH_BINARY);//二值化阈值
//threshold(gray, dst, threshold_value, threshold_max, THRESH_BINARY_INV);//反向二值化阈值
threshold(gray, dst, threshold_value, threshold_max, type_value);
imshow(output_title, dst);
}
threshold(gray, dst, 0, 255,THRESH_OTSU | type_value);//自动计算阈值
或者
threshold(gray, dst, 0, 255, THRESH_TRIANGLE | type_value);//自动计算阈值(直方)
这个操作可以自动计算阈值,将原代码中 threshold(gray, dst, threshold_value, threshold_max, type_value);替换即可。
PS:灰度图像才能进行阈值操作。