目录
图像增强
图像增强——RGB图分离并均衡化
Mat src = imread(argv[i]);
Mat imageRGB[3];
split(src, imageRGB);
for (int i = 0; i < 3; i++)
{
equalizeHist(imageRGB[i], imageRGB[i]);
}
merge(imageRGB, 3, src);
图像增强——RGB图分离并对数log变换
Mat image = imread(argv[i]);
Mat imageLog(image.size(), CV_32FC3);
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
imageLog.at<Vec3f>(i, j)[0] = log(1 + image.at<Vec3b>(i, j)[0]);
imageLog.at<Vec3f>(i, j)[1] = log(1 + image.at<Vec3b>(i, j)[1]);
imageLog.at<Vec3f>(i, j)[2] = log(1 + image.at<Vec3b>(i, j)[2]);
}
}
//归一化到0~255
normalize(imageLog, imageLog, 0, 255, CV_MINMAX);
//转换成8bit图像显示
convertScaleAbs(imageLog, imageLog);
图像增强——滤波器
// 滤波器
void sharpenImage(const cv::Mat &image, cv::Mat &result)
{
//创建并初始化滤波模板
/*滤波核为拉普拉斯核3x3:
0 -1 0
-1 5 -1
0 -1 0
*/
cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0));
kernel.at<float>(0, 1) = -1.0;
kernel.at<float>(1, 0) = -1.0;
kernel.at<float>(1, 1) = 5.0;
kernel.at<float>(1, 2) = -1.0;
kernel.at<float>(2, 1) = -1.0;
result.create(image.size(), image.type());
//对图像进行滤波
cv::filter2D(image, result, image.depth(), kernel);
}
图像增强——高反差
Mat HighPass(Mat img)
{
Mat temp;
GaussianBlur(img, temp, Size(7, 7), 1.6, 1.6);
int r = 3;
Mat diff = img + r*(img - temp); //高反差保留算法
return diff;
}
图像增强——边缘增强
void edgeEnhance(cv::Mat& srcImg, cv::Mat& dstImg)
{
if (!dstImg.empty())
{
dstImg.release();
}
std::vector<cv::Mat> rgb;
if (srcImg.channels() == 3) // rgb image
{
cv::split(srcImg, rgb);
}
else if (srcImg.channels() == 1) // gray image
{
rgb.push_back(srcImg);
}
// 分别对R、G、B三个通道进行边缘增强
for (size_t i = 0; i < rgb.size(); i++)
{
cv::Mat sharpMat8U;
cv::Mat sharpMat;
cv::Mat blurMat;
// 高斯平滑
cv::GaussianBlur(rgb[i], blurMat, cv::Size(3, 3), 0, 0);
// 计算拉普拉斯
cv::Laplacian(blurMat, sharpMat, CV_16S);
// 转换类型
sharpMat.convertTo(sharpMat8U, CV_8U);
cv::add(rgb[i], sharpMat8U, rgb[i]);
}
cv::merge(rgb, dstImg);
}
形态学——膨胀
图像分割
图像分割——OTSU阈值
//otsu阈值自动求取
double getThreshVal_Otsu(const cv::Mat& _src)
{
cv::Size size = _src.size();
if (_src.isContinuous())
{
size.width *= size.height;
size.height = 1;
}
const int N = 256;
int i, j, h[N] = { 0 };
for (i = 0; i < size.height; i++)
{
const uchar* src = _src.data + _src.step*i;
for (j = 0; j <= size.width - 4; j += 4)
{
int v0 = src[j], v1 = src[j + 1];
h[v0]++; h[v1]++;
v0 = src[j + 2]; v1 = src[j + 3];
h[v0]++; h[v1]++;
}
for (; j < size.width; j++)
h[src[j]]++;
}
double mu = 0, scale = 1. / (size.width*size.height);
for (i = 0; i < N; i++)
mu += i*h[i];
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for (i = 0; i < N; i++)
{
double p_i, q2, mu2, sigma;
p_i = h[i] * scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if (std::min(q1, q2) < FLT_EPSILON || std::max(q1, q2) > 1. - FLT_EPSILON)
continue;
mu1 = (mu1 + i*p_i) / q1;
mu2 = (mu - q1*mu1) / q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
if (sigma > max_sigma)
{
max_sigma = sigma;
max_val = i;
}
}
return max_val;
}
图像分割——Kmeans
Mat Image_Kmeans(Mat src, int n)
{
int width = src.cols;
int height = src.rows;
int dims = src.channels();
// 初始化定义
int sampleCount = width*height;
int clusterCount = n;//分几类
Mat points(sampleCount, dims, CV_32F, Scalar(10));
Mat labels;
Mat centers(clusterCount, 1, points.type());
// 图像RGB到数据集转换
int index = 0;
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
index = row*width + col;
Vec3b rgb = src.at<Vec3b>(row, col);
points.at<float>(index, 0) = static_cast<int>(rgb[0]);
points.at<float>(index, 1) = static_cast<int>(rgb[1]);
points.at<float>(index, 2) = static_cast<int>(rgb[2]);
}
}
// 运行K-Means数据分类
TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
// 显示图像分割结果
Mat result = Mat::zeros(src.size(), CV_8UC3);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
index = row*width + col;
int label = labels.at<int>(index, 0);
if (label == 1) {
result.at<Vec3b>(row, col)[0] = 255;
result.at<Vec3b>(row, col)[1] = 0;
result.at<Vec3b>(row, col)[2] = 0;
}
else if (label == 2){
result.at<Vec3b>(row, col)[0] = 0;
result.at<Vec3b>(row, col)[1] = 255;
result.at<Vec3b>(row, col)[2] = 0;
}
else if (label == 3) {
result.at<Vec3b>(row, col)[0] = 0;
result.at<Vec3b>(row, col)[1] = 0;
result.at<Vec3b>(row, col)[2] = 255;
}
else if (label == 0) {
result.at<Vec3b>(row, col)[0] = 0;
result.at<Vec3b>(row, col)[1] = 255;
result.at<Vec3b>(row, col)[2] = 255;
}
}
}
return result;
}
图像滤波
多种滤波器
https://blog.csdn.net/zoucharming/article/details/70197863
在图像处理中,尽可能消除图片中的噪声,消除噪声就需要用到滤波,在本次opencv学习中,学习了三个滤波方式。
(1)平均滤波,就是将一个区域内的像素值求和取平均值,然后用这个平均值替换区域中心的像素值。
blur(源Mat对象,目标Mat对象,Size对象,Point对象)//Size对象用来确定区域大小,Point对象如果x,y都是-1则表示更新区域中心的像素。
(2)高斯滤波,也是将一个区域的像素值求取平均值替换区域中心的像素值,但是是加权平均,权重按照二维正态分布。
GaussianBlur(源Mat对象,目标Mat对象,Size对象,x方向正太分布参数,y方向正太分布参数)
(3)中值滤波,之前的两个滤波都有个问题,如果区域中有极端值,很可能影响滤波效果,中值滤波采用区域中的中值来替换,有利于克服椒盐噪声。
medianBlur(源Mat对象,目标Mat对象,int size)//这里的size表示正方形区域的边长
(4)双边滤波,之前的滤波还有个问题,他们都会把轮廓给模糊了,有一些区域之间相差较大的像素,这往往能看出轮廓,所以如果我们给个限制范围,如果两点间的像素值差距大于这个范围就不滤波了,保留图像轮廓
bilateralFilter(源Mat对象,目标Mat对象,int 区域半径,int 限制范围,int space)//space是当区域半径给的是0时,用来计算区域范围的,一般情况下没用,随便给个数就行。
#include<opencv2\opencv.hpp>
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
using namespace cv;
int main()
{
Mat src;
src = imread("1.jpg", 1);
if (src.empty())
{
printf("cannot load!!\n");
return -1;
}
namedWindow("原图");
imshow("原图", src);
Mat dst,dst1;
blur(src, dst, Size(3, 3), Point(-1, -1));
namedWindow("均值滤波");
imshow("均值滤波", dst);
GaussianBlur(src, dst, Size(5, 5), 5, 5);
namedWindow("高斯滤波");
imshow("高斯滤波", dst);
medianBlur(src, dst, 5);
namedWindow("中值滤波");
imshow("中值滤波", dst);
bilateralFilter(src, dst, 5, 100, 3);
namedWindow("双边滤波");
imshow("双边滤波", dst);
waitKey(0);
return 0;
}