图像腐蚀
作用:将目标元素收缩。面积较小的连通域可以通过腐蚀操作消除,从而减少噪声导致的计数错误。
步骤:
- 构建结构元素
- 扫描原图,找到第一个像素为1的点(因为是二值图,非0即1)
- 将预先设定好的形状以及原点位置的结构元素的原点移动到该点
- 判断该结构元素覆盖范围内的图像的像素值是否全部为1,如果是,则腐蚀后图像相同位置上的像素值为1,如果至少有一个像素值为0,则腐蚀后图像的相同位置上的像素值为0
- 对原图中所有像素值为1的点重复进行步骤3和4
结构元素:矩形、十字、椭圆
在腐蚀多通道时,每个通道独立进行腐蚀运算
腐蚀过程只针对非零元素,所以零像素背景,腐蚀操作后图像内容变瘦小;255像素背景,腐蚀操作后图像内容变粗大
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
//绘制包含区域函数
void drawState(Mat& img, int number, Mat centroid, Mat stats, String str) {
//生成随机颜色,用于区分不同连通域
RNG rng(10086);
vector<Vec3b> colors;
for (int i = 0; i < number; i++) {
//使用均匀分布的随机数确定颜色
Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
colors.push_back(vec3);
}
for (int i = 1; i < number; i++) {
//中心位置
int center_x = centroid.at<double>(i, 0);
int center_y = centroid.at<double>(i, 1);
//矩形边框
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int w = stats.at<int>(i, CC_STAT_WIDTH);
int h = stats.at<int>(i, CC_STAT_HEIGHT);
int area = stats.at<int>(i, CC_STAT_AREA);
//中心位置绘制
circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);
//外接矩阵
Rect rect(x, y, w, h);
rectangle(img, rect, colors[i], 1, 8, 0);
putText(img, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
cout << "number" << i << ",area" << area << endl;
}
imshow("str", img);
}
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
//生成用于腐蚀的原图
Mat src = (Mat_<uchar>(6, 6) << 0, 0, 0, 0, 255, 0,
0, 255, 255, 255, 255, 255,
0, 255, 255, 255, 255, 0,
0, 255, 255, 255, 255, 0,
0, 255, 255, 255, 255, 0,
0, 0, 0, 0, 0, 0);
Mat struct1, struct2;
struct1 = getStructuringElement(0, Size(3, 3)); //矩形结构元素
struct2 = getStructuringElement(1, Size(3, 3)); //十字结构元素
Mat erodeSrc; //存放腐蚀后的图像
erode(src, erodeSrc, struct2);
namedWindow("src", WINDOW_GUI_NORMAL);
namedWindow("erodeSrc", WINDOW_GUI_NORMAL);
imshow("src", src);
imshow("erodeSrc", erodeSrc);
Mat LearnCV_black= imread("D:/images/ren.jpg",IMREAD_ANYCOLOR);
Mat LearnCV_write = imread("D:/images/wu.jpeg", IMREAD_ANYCOLOR);
Mat erode_black1, erode_write1, erode_black2, erode_write2;
//黑色背景图像腐蚀
erode(LearnCV_black, erode_black1,struct1);
erode(LearnCV_black, erode_black2, struct2);
imshow("LearnCV_black", LearnCV_black);
imshow("erode_black1", erode_black1);
imshow("erode_black2", erode_black2);
//白色背景图像腐蚀
erode(LearnCV_write, erode_write1, struct1);
erode(LearnCV_write, erode_write2, struct2);
imshow("LearnCV_write", LearnCV_write);
imshow("erode_write1", erode_write1);
imshow("erode_write2", erode_write2);
//验证腐蚀对小连通的去除
Mat img = imread("D:/images/hua.jpeg");
Mat img2;
copyTo(img, img2, img);
Mat rice, riceBW;
//把图像转成二值图像
cvtColor(img, rice, COLOR_BGR2GRAY); //彩色-->灰度
threshold(rice, riceBW, 50, 255, THRESH_BINARY); //二值化
Mat out, stats, centroid;
int number = connectedComponentsWithStats(riceBW, out, stats, centroid, 8, CV_16U);
drawState(img, number, centroid, stats, "未腐蚀时统计连通域");
erode(riceBW, riceBW, struct1); //对图像进行腐蚀
number = connectedComponentsWithStats(riceBW, out, stats, centroid, 8, CV_16U);
drawState(img2, number, centroid, stats, "腐蚀后统计连通域");
waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
//destroyAllWindows();
return 0;
}
图像膨胀
图像膨胀是图像腐蚀的相反过程
作用:连接图像中间隔的物体;填充小孔;增加物体大小;去除小物体;去除噪声;提取信息
过程:
结构元素
原图
把核中心放在第一个元素:
最终效果:
在膨胀多通道时,每个通道独立进行膨胀运算
膨胀过程只针对非零元素,所以零像素背景,膨胀操作后图像内容变粗大;255像素背景,膨胀操作后图像内容变瘦小
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
#include<math.h>
#include <opencv2/imgproc.hpp>
#include<vector>
using namespace cv;
using namespace std;
Mat pixel_visit_demo(Mat& src) {
Mat image ;
image = src.clone(); //克隆
int w = image.cols;
int h = image.rows;
int dims = image.channels();
/*
//数组
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
if (dims == 1) { //单通道灰度图
int pv = image.at<uchar>(row, col); //得到像素值(行,列)
image.at<uchar>(row, col) = 255 - pv; //给像素值重新赋值(取反)
}
if (dims == 3) { //三通道彩色图
Vec3b bgr = image.at<Vec3b>(row, col); //opencv特定类型,获取三维颜色,3个值
image.at<Vec3b>(row, col)[0] = 255 - bgr[0]; //对彩色图像读取像素值,并改写
image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
}
}
}*/
//指针
for (int row = 0; row < h; row++) {
uchar* current_row = image.ptr<uchar>(row);
for (int col = 0; col < w; col++) {
if (dims == 1) {//灰度图
int pv = *current_row;
*current_row++ = 255 - pv;
}
if (dims == 3) {//彩色图
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
*current_row++ = 255 - *current_row;
}
}
}
return( image);
};
int main(int argc, char** argv) {
//QuickDemo qd;
//qd.myFilter_demo(src);
//生成用于腐蚀的原图
Mat src = (Mat_<uchar>(6, 6) << 0, 0, 0, 0, 255, 0,
0, 255, 255, 255, 255, 255,
0, 255, 255, 255, 255, 0,
0, 255, 255, 255, 255, 0,
0, 255, 255, 255, 255, 0,
0, 0, 0, 0, 0, 0);
Mat struct1, struct2;
struct1 = getStructuringElement(0, Size(3, 3)); //矩形结构元素
struct2 = getStructuringElement(1, Size(3, 3)); //十字结构元素
Mat dilateSrc; //存放膨胀后的图像
dilate(src, dilateSrc, struct2);
namedWindow("src", WINDOW_GUI_NORMAL);
namedWindow("dilateSrc", WINDOW_GUI_NORMAL);
imshow("src", src);
imshow("dilateSrc", dilateSrc);
Mat LearnCV_black= imread("D:/images/black.png",IMREAD_ANYCOLOR);
Mat LearnCV_write = pixel_visit_demo(LearnCV_black);
Mat dilate_black1, dilate_write1, dilate_black2, dilate_write2;
//黑色背景图像膨胀
dilate(LearnCV_black, dilate_black1,struct1);
dilate(LearnCV_black, dilate_black2, struct2);
imshow("LearnCV_black", LearnCV_black);
imshow("dilate_black1", dilate_black1);
imshow("dilate_black2", dilate_black2);
//白色背景图像腐蚀
dilate(LearnCV_write, dilate_write1, struct1);
dilate(LearnCV_write, dilate_write2, struct2);
imshow("LearnCV_write", LearnCV_write);
imshow("dilate_write1", dilate_write1);
imshow("dilate_write2", dilate_write2);
//比较腐蚀和膨胀的结果
Mat erode_black1, resultXor, resultAnd;
erode(LearnCV_black, erode_black1, struct1);
bitwise_xor(erode_black1, dilate_write1, resultXor);
bitwise_and(erode_black1, dilate_write1, resultAnd);
imshow("resultXor", resultXor);
imshow("resultAnd", resultAnd);
waitKey(0);//此时图片显示时间为一直停留。(x)为x毫秒
//destroyAllWindows();
return 0;
}