1.二值化
#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
Mat Judge(Mat input, int h, int w, int rmin, int max);
Mat State(Mat src);
//获取图像最大灰度级和最小灰度级
int main()
{
std::string image_path = "bj.bmp";
//读入原灰度图像
Mat img_source = imread(image_path, IMREAD_GRAYSCALE);
//如果为空的话提示打不开
if (img_source.empty())
{
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
//定义判断法和状态法的图像
Mat Anal;
Mat Sta;
int rmin = 0;
int rmax = 255;
int h{
img_source.rows }; // 图片高
int w{
img_source.cols }; // 图片宽度
namedWindow("【原图】");
imshow("【原图】", img_source);
Anal = Judge(img_source, h, w, rmin, rmax);
namedWindow("【判断分析图】");
imshow("【判断分析图】", img_source);
img_source = imread(image_path, IMREAD_GRAYSCALE);
Sta = State(img_source);
namedWindow("【状态图】");
imshow("【状态图】", img_source);
int k = waitKey(1055500); // Wait for a keystroke in the window
if (k == 'J')
{
//保存图片
imwrite("Judge_0.bmp", Anal);
}
else
imwrite("State_0.bmp", Sta);
return 0;
}
Mat Judge(Mat input, int h, int w, int rmin, int rmax)
{
//参考实习教材
int T = 0;
int hist[256];
unsigned char* ptr = input.data;
memset(hist, 0, sizeof(hist));
int S, S1, S2;
double P, P1;
double mean1, mean2;
double D1, D2, classinDis, classoutDis;
double Tmax;
int graymin = 255, graymax = 0;
int i, j;
int k = 0;
//统计灰度直方图,各个灰度级个数
for (i = 0; i<h; i++)
for (j = 0; j < w; j++)
{
int gray = ptr[i*w + j];
hist[gray]++;
if (gray > graymax) graymax = gray;
if (gray < graymin) graymin = gray;
}
P = 0.0;
S = 0;
if (graymin == 0)
graymin++;
//计算总的质量矩P和像素总数S
for (k = graymin; k <= graymax; k++)
{
P += (double)k*(double)hist[k];
S += hist[k];
}
Tmax = 0.0;
S1 = 0, S2 = 0;
P1 = 0.0;
D1 = 0.0;
D2 = 0.0;
classinDis = 0.0;
classoutDis = 0.0;
double ratio = 0.0;
//求阈值
for (k = graymin; k <= graymax; k++)
{
//计算1类像素的个数
S1 += hist[k];
if (!S1)
{
continue;
}
//计算2类像素的个数
S2 = S - S1;
if (S2 == 0)
{
break;
}
//计算1类质量矩
P1 += (double)k*hist[k];
//计算1类均值
mean1 = P1 / S1;
//计算1类间方差
for (int n = graymin; n <= k; n++)
{
D1 += ((n - mean1)*(n - mean1)*hist[n]);
}
//同上
mean2 = (P - P1) / S2;
for (int m = k + 1; m <= graymax; m++)
{
D2 += ((m - mean2)*(m - mean2)*hist[m]);
}
classinDis = D1 + D2;
classoutDis = (double)S1*(double)S2*(mean1 - mean2)*(mean1 - mean2);
if (classinDis != 0)
ratio = classoutDis / classinDis;
if (ratio >Tmax)
{
Tmax = ratio;
T = k;
}
}
//二值化
for (i = 0; i < h; i++)
for (j = 0; j < w; j++) {
if (ptr[i*w + j] < T)
ptr[i*w + j] = 0;
else ptr[i*w + j] = 255;
}
return input;
}
Mat State(Mat src)
{
//参考教程
int iThrehold;//阀值
int height = src.rows;
int width = src.cols;
unsigned char *ptr = src.data;
int iDiffRec = 0;
int hist[256] = {
0 }; //直方图数组
int iTotalGray = 0;//灰度值和
int iTotalPixel = 0;//像素数和
int gray;//某点的像素值
int iNewThrehold;//新阀值
int iMaxGrayValue = 0, iMinGrayValue = 255;//原图像中的最大灰度值和最小灰度值
int iMeanGrayValue1, iMeanGrayValue2;
//获取(i,j)的值,存于直方图数组F
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
gray = ptr[j*width + i];
if (gray < iMinGrayValue)
iMinGrayValue = gray;
if (gray> iMaxGrayValue)
iMaxGrayValue = gray;
hist[gray]++;
}
}
iThrehold = 0;
iNewThrehold = (iMinGrayValue + iMaxGrayValue) / 2;//初始阀值
iDiffRec = iMaxGrayValue - iMinGrayValue;
for (int a = 0; (abs(iThrehold - iNewThrehold) > 0.5); a++)//迭代中止条件
{
iThrehold = iNewThrehold;
//小于当前阀值部分的平均灰度值
for (int i = iMinGrayValue; i < iThrehold; i++)
{
iTotalGray += hist[i] * i;//hist[]存储图像信息
iTotalPixel += hist[i];
}
iMeanGrayValue1 = (double)(iTotalGray / iTotalPixel);
//大于当前阀值部分的平均灰度值
iTotalPixel = 0;
iTotalGray = 0;
for (int j = iThrehold + 1; j < iMaxGrayValue; j++)
{
iTotalGray += hist[j] * j;//hist[]存储图像信息
iTotalPixel += hist[j];
}
iMeanGrayValue2 = (double)(iTotalGray / iTotalPixel);
iNewThrehold = (iMeanGrayValue2 + iMeanGrayValue1) / 2; //新阀值
iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
}
//二值化
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
if (ptr[i*width + j] < iThrehold)
ptr[i*width + j] = 0;
else ptr[i*width + j] = 255;
}
return src;
}
结果图:
2.线性拉伸
// Linear _stretch.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
//获取图像最大灰度级和最小灰度级
int RminRmax(Mat input, int &rmin, int& rmax);
/*
//图像对比度拉伸。
//(r1,s1)灰度平面上的第一个点
//(r2,s2)灰度平面上的第二个点
*/
Mat Stretch(Mat input, int r1, int s1, int r2, int s2, int rmin, int rmax);
int InsertSort(int arr[], int size);
int main()
{
std::string image_path = "bj.bmp";
//读入原灰度图像
Mat img_source = imread(image_path, IMREAD_GRAYSCALE);
//如果为空的话提示打不开
if (img_source.empty())
{
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
int h{
img_source.rows }; // 图片高
int w{
img_source.cols }; // 图片宽度
namedWindow("【原图】");
imshow("【原图】", img_source);
Mat img_pro;//拉伸处理后的图像
int rmin = 0;
int rmax = 0;
RminRmax(img_source, rmin, rmax);
//h灰度拉伸
img_pro = Stretch(img_source, 105, 40, 230, 220,rmin,rmax);
namedWindow("【线性变换图】");
imshow("【线性变换图】", img_pro);
int k = waitKey(1055500); // Wait for a keystroke in the window
if (k == 'w')
{
//保存图片
imwrite("1_0.bmp", img_pro);
}
return 0;
}
int RminRmax(Mat input, int &rmin, int &rmax)
{
int h{
input.rows }; // 图片高
int w{
input.cols }; // 图片宽
uchar* data_in{
input.data }; // 原图图片像素数据
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
{
if (rmin>data_in[y*w + x])
rmin = data_in[y*w + x];
if (rmax < data_in[y*w + x])
rmax = data_in[y*w + x];
}
return 0;
}
//线性变化
Mat Stretch(Mat input, int r1, int s1, int r2, int s2, int rmin, int rmax)
{
//(r1s1) (r2,s2)
int h{
input.rows }; // 图片高
int w{
input.cols }; // 图片宽度
unsigned char* ptr = input.data;
double data; //灰度
double k, k1, k2, k3, b, b1, b2, b3; // 直线斜率与截距
k1 = (double)(s1 - rmin) / (double)(r1 - rmin);
b1 = 0;
k2 = (double)(s2 - s1) / (double)(r2 - r1);
b2 = s1 - k2*r1;
k3 = (rmax - s2) / (rmax - r2);
b3 = s2 - k3*r2;
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
{
data = ptr[y*w + x];
if (data <= r1)
{
k = k1;
b = b1;
}
else if (data >= r2)
{
k = k3;
b = b3;
}
else
{
k = k2;
b = b2;
}
data = k*data + b;
ptr[y*w + x] = (data);
}
return input;
}
//获取图片灰度值最大值与最小值
int RmimRmax(Mat input, int &rmin, int& rmax)
{
int h{
input.rows }; // 图片高
int w{
input.cols }; // 图片宽
uchar* data_in{
input.data }; // 原图图片像素数据
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++)
{
if (rmin>data_in[y*w + x])
rmin = data_in[y*w + x];
if (rmax < data_in[y*w + x])
rmax = data_in[y*w + x];
}
return 0;
}
3.高低通,中值滤波
#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
//像素点的位置数组
int dx[] = {
-1,0,1,-1,0,1,-1,0,1 };
int dy[] = {
-1,-1,-1,0,0,0,1,1,1 };
using namespace cv;
//中值滤波
Mat image_filter_median(Mat img_source, Mat dst);
int InsertSort(int arr[], int size);
//高低通
Mat HighPass(Mat src, int h, int w);
Mat LowPass(Mat src, int h, int w);
int main()
{
std::string image_path = "bj.bmp";
//读入原灰度图像
Mat img_source = imread(image_path, IMREAD_GRAYSCALE);
//如果为空的话提示打不开
if (img_source.empty())
{
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
int h{
img_source.rows }; // 图片高
int w{
img_source.cols }; // 图片宽度
namedWindow("【原图】");
imshow("【原图】", img_source);
Mat dst;//中值滤波
dst.create(img_source.size(), img_source.type());
dst=image_filter_median(img_source, dst);
namedWindow("【中值滤波图】");
imshow("【中值滤波图】", dst);
Mat Low;//低通滤波图像
Mat High;
High=HighPass(img_source, h, w);
namedWindow("【高通滤波图】");
imshow("【高通滤波图】", High);
Low=LowPass(img_source, h, w);
namedWindow("【低通滤波图】");
imshow("【低通滤波图】", Low);
int k = waitKey(1055500); // Wait for a keystroke in the window
if (k == 'm')
{
//保存图片
imwrite("2_0.bmp", dst);
}
else if (k == 'H')
{
//保存图片
imwrite("3_0.bmp",High );
}
else imwrite("4_0.bmp", Low);
return 0;
}
//插入排序,返回中间值
int InsertSort(int arr[], int size)
{
for (int i = 1; i < size; i++)
{
int temp = arr[i];
int j = i - 1;
while (j >= 0)
{
if (arr[j] > temp)arr[j + 1] = arr[j];
else break;
j--;
}
arr[j + 1] = temp;
}
return arr[4];
}
//中值滤波
Mat image_filter_median(Mat img_source, Mat dst)
{
for (int i = 0; i <img_source.rows; i++) {
for (int j = 0; j < img_source.cols; j++) {
if ((i - 1) >= 0 && (i + 1) <img_source.rows && (j - 1) >= 0 && (j + 1) < img_source.cols)
{
int d[9];
for (int k = 0; k < 9; ++k) {
int gray = img_source.at<uchar>(i + dx[k], j + dy[k]);
d[k] = gray;
}
dst.at<uchar>(i, j) = InsertSort(d, 9);
}
else {
int gray = img_source.at<uchar>(i, j);
dst.at<uchar>(i, j) = gray;
}
}
}
return dst;
}
//高通滤波
Mat HighPass(Mat src, int h,int w)
{
int i, j;
unsigned char *ptr = src.data;
Mat ResultImage(h, w, src.type());
unsigned char *ptr2 = ResultImage.data;
unsigned char *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9 ;
for(int i=1;i<h-1;i++)
for (int j = 1; j < w - 1; j++)
{
p1 = &ptr[ w*(i - 1) + (j - 1) ];
p2 = &ptr[w*(i ) + (j - 1)];
p3= &ptr[w*(i + 1) + (j - 1)];
p4 = &ptr[w*(i - 1) + (j)];
p5 =&ptr2[w*(i ) + (j ) ];
p6 = &ptr[w*(i + 1) + (j )];
p7 = &ptr[w*(i - 1) + (j + 1)];
p8 = &ptr[w*(i) + (j + 1)];
p9 = &ptr[w*(i+1) + (j+ 1)];
*p5=ptr[ w*(i)+(j)];
int t = (int)(*p5 * 9 - *p1 - *p2 - *p3 - *p4 - *p5 - *p6 - *p7 - *p8 - *p9);
if (t > 255)
*p5 = 255;
else if (t < 0)
*p5 = 0;
else *p5 = t;
ptr2[w*(i-1) + j-1] = *p5;
}
return ResultImage;
}
Mat LowPass(Mat src, int h, int w)
{
int i, j;
unsigned char *ptr = src.data;
Mat ResultImage(h, w, src.type());
unsigned char *ptr2 = ResultImage.data;
unsigned char *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
for (int i = 1; i<h - 1; i++)
for (int j = 1; j < w - 1; j++)
{
p1 = &ptr[w*(i - 1) + (j - 1)];
p2 = &ptr[w*(i)+(j - 1)];
p3 = &ptr[w*(i + 1) + (j - 1)];
p4 = &ptr[w*(i - 1) + (j)];
p5 = &ptr2[w*(i)+(j)];
p6 = &ptr[w*(i + 1) + (j)];
p7 = &ptr[w*(i - 1) + (j + 1)];
p8 = &ptr[w*(i)+(j + 1)];
p9 = &ptr[w*(i + 1) + (j + 1)];
*p5 = ptr[w*(i)+(j)];
int t = (int)( (*p1 + *p2 + *p3 + *p4 + *p5 +*p6+ *p7 + *p8 + *p9)/9);
if (t > 255)
*p5 = 255;
else if (t < 0)
*p5 = 0;
else *p5 = t;
ptr2[w*(i - 1) + j - 1] = *p5;
}
return ResultImage;
}
4.缩放,平移,旋转
// Translation _rotation.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
Mat Translation(Mat src, int h, int w, int nX, int nY);
Mat Shrink(Mat src, float scale, int h, int w);
Mat Rotate(Mat src, float angle, int h, int w);
int main()
{
std::string image_path = "bj.bmp";
//读入原灰度图像
Mat img_source = imread(image_path, IMREAD_GRAYSCALE);
Mat Trans;
Mat Shrink1;
Mat Rotate1;
//如果为空的话提示打不开
if (img_source.empty())
{
std::cout << "Could not read the image: " << image_path << std::endl;
return 1;
}
int h{
img_source.rows }; // 图片高
int w{
img_source.cols }; // 图片宽度
namedWindow("【原图】");
imshow("【原图】", img_source);
Trans=Translation(img_source, h, w, 35, 50);
namedWindow("【平移】");
imshow("【平移】", Trans);
Shrink1=Shrink(img_source, 0.5, h, w);
namedWindow("【缩放】");
imshow("【缩放】", Shrink1);
Rotate1=Rotate(img_source, 30, h, w);
namedWindow("【旋转】");
imshow("【旋转】",Rotate1);
int k = waitKey(1055500); // Wait for a keystroke in the window
if (k == 'T')
{
//保存图片
imwrite("T_0.bmp", Trans);
}
else if(k=='S')
imwrite("S_0.bmp", Shrink1);
else imwrite("R_0.bmp", Rotate1);
return 0;
}
//平移
Mat Translation(Mat src, int h, int w, int nX, int nY)
{
Mat ResultImage(h, w, src.type());
unsigned char *ptr = src.data;
unsigned char *ptr2 = ResultImage.data;
for (int i = 0; i < h; i++)
{
//y是变换后的坐标=当前行号+变换Y
int y = (i + nY);
for (int j = 0; j < w; j++)
{
//x是变换后的坐标=当前列号+变换X
int x = (j + nX);
if (y< h && x<w)
{
//行列坐标要位于(w,h)内
//交换位置
ptr2[x + y*w] = ptr[j + i*w];
}
}
}
return ResultImage;
}
Mat Shrink(Mat src, float scale, int h, int w)
{
//scale是缩小的比例
//高度和宽度放缩后的大小为m1,m2
int m1 = floor(h*scale);
int n1 = floor(w*scale);
Mat ResultImage = Mat::zeros(m1, n1, src.type());
unsigned char *ptr = src.data;
unsigned char *ptr2 = ResultImage.data;
//分别得到x,y的变化
float ScaleY = float(m1) / float(h);
float ScaleX = float(n1) / float(w);
//分配内存
for (int i = 0; i < m1; i++)
{
//变化后的坐标
float InvY = float(i) / ScaleY;
float Y = floor(InvY);
//变换了多少
float Dy = InvY - Y;
for (int j = 0; j < n1; j++)
{
float InvX = float(j) / ScaleX;
float X = floor(InvX);
float Dx = InvX - X;
//取整
int x = int(X);
int y = int(Y);
ptr2[j + i*n1] = (1 - Dy)*(1 - Dx)*ptr[x + y*w] + Dy*(1 - Dx)*ptr[x + (y + 1)*w]
+ (1 - Dy)*Dx*ptr[x + 1 + y *w]
+ Dy*Dx*ptr[x + 1 + (y + 1) *w];
}
}
Mat ResultImage1;
ResultImage.convertTo(ResultImage1, CV_8UC1);
return ResultImage;
}
//旋转
float *Sin_Cos(float x,float y, float sin, float cos)
{
float n[2] = {
0};
n[0] = cos*x + sin*y;
n[1] = -sin*x + cos*y;
return n;
}
Mat Rotate(Mat src, float angle, int h, int w)
{
Mat ResultImage = Mat::zeros(h, w, src.type());
unsigned char *ptr = src.data;
float SinAngle, CosAngle;
//旋转后的图像宽高
int newH, newW;
int i0, j0;
//图像四个角的坐标/变换后的坐标
int SrcX[4] = {
0 };
int SrcY[4] = {
0 };
int DstX[4] = {
0 };
int DstY[4] = {
0 };
//角度转为弧度
float RotateAngle = angle*3.1415926 / 180;
SinAngle = (float)(sin((double)RotateAngle));
CosAngle = (float)(cos((double)RotateAngle));
SrcX[0] = (float)(-(w - 1) / 2);SrcY[0] = (float)((h - 1) / 2);
SrcX[1] = (float)((w - 1) / 2);SrcY[1] = (float)((h - 1) / 2);
SrcX[2] = (float)(-(w - 1) / 2);SrcY[2] = (float)(-(h - 1) / 2);
SrcX[3] = (float)((w - 1) / 2);SrcY[3] = (float)(-(h - 1) / 2);
for (int i = 0; i < 4; i++)
{
float *n = Sin_Cos(SrcX[i], SrcY[i], SinAngle, CosAngle);
DstX[i] = n[0];
DstY[i] = n[1];
}
float f1, f2;
newW = (long)(max(fabs(DstX[3] - DstX[0]), fabs(DstX[2] - DstX[1] + 0.5)));
newH=(long)(max(fabs(DstY[3] - DstY[0]), fabs(DstY[2] - DstY[1] + 0.5)));
f1 = (float)(-0.5*(newW - 1)*CosAngle - 0.5*(newH - 1)*SinAngle + 0.5*(newW - 1));
f2 = (float)(0.5*(newW - 1)*SinAngle - 0.5*(newH - 1)*CosAngle + 0.5*(newH - 1));
int i, j;
ResultImage = Mat::zeros(newH, newW, src.type());
unsigned char *ptr2 = ResultImage.data;
for (i = 0; i <newH; i++)
{
for (j = 0; j <newW; j++)
{
i0 = (-((float)j))*SinAngle + ((float)i)*CosAngle + f2 + 0.5;
j0 = (((float)j))*CosAngle + ((float)i)*SinAngle + f1 + 0.5;
if ((j0 >= 0) && (j0 < w) && (i0 >= 0) && (i0 < h))
ptr2[i*newW + j]=ptr[i0*w + j0];
else ptr2[i*newW + j] = 0;
}
}
return ResultImage;
}