数字图像处理(二值化,高通,低通滤波,中值滤波,线性灰度拉伸,缩放,平移旋转)OpenCV

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;

}

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_46877697/article/details/115220721