【Opencv学习】灰度变换和直方图修正

一、灰度变换

灰度变换概述:灰度变换通过扩展输入图像的动态范围以达到图像增强的目的
灰度变换的作用:(1)改善图像的质量,提高图像的对比度
(2)有选择地突出图像感兴趣的特征或抑制图像中不需要的特征
(3)有效地改变图像打的直方图分布,使像素的分布更加均匀

1.由加权平均法实现RGB图像转灰度图像

加权平均值法公式:D=0.299R+0.587G+0.114*B
其中D表示为点(x,y)转换后的灰度值,R、G、B为点(x,y)的三个单色分量
代码如下(示例):


#include "pch.h"
#include <iostream>
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

void grayImageShow(cv::Mat &input, cv::Mat &output)
{
	for (int i = 0; i < input.rows; ++i)
		for (int j = 0; j < input.cols; ++j)
			output.at<uchar>(i, j) = cv::saturate_cast<uchar>(0.114*input.at<cv::Vec3b>(i, j)[0] + 0.587*input.at<cv::Vec3b>(i, j)[1] + 0.2989*input.at<cv::Vec3b>(i, j)[2]);
	cv::imshow("由经验公式得到的灰度图像", output);
}

int main(void)
{
	cv::Mat src, gray, dst;

	gray = cv::imread("Lena.jpg", cv::IMREAD_GRAYSCALE);//由imread()得到的灰度图像
	src = cv::imread("Lena.jpg");
	dst.create(src.rows, src.cols, CV_8UC1);

	cv::imshow("scr", src);
	cv::imshow("由imread得到的灰度图像", gray);
	grayImageShow(src, dst);//由经验公式得到的灰度图像
	waitKey(-1); //按键后再继续

	return 0;
}

2 . 线性灰度变换

图像的线性变换是图像处理的基本运算,通常应用在调整图像的画面质量方面,如图像对比度、亮度对比及反转等操作。通过线性灰度变换可以将图像的灰度动态范围按线性关系式扩展到指定范围。
代码如下(示例):


#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
#pragma comment(lib, "opencv_world460d.lib")  //引用引入库 

// 图像线性变换操作
cv::Mat linearTransform(cv::Mat srcImage, float a, int b)
{
    if(srcImage.empty()){  
        std::cout<< "No data!" <<std::endl;  
    } 
    const int nRows = srcImage.rows;
    const int nCols = srcImage.cols;
    cv::Mat resultImage = 
        cv::Mat::zeros(srcImage.size(), srcImage.type());
    // 图像元素遍历
    for( int i = 0; i < nRows; i++ )
    {
        for( int j = 0; j < nCols; j++ )
        {
            for( int c = 0; c < 3; c++ )//如果源图像是灰度图,那么把这里改为c<1即可
            {
                // 矩阵at操作,检查下标防止越界
                resultImage.at<Vec3b>(i,j)[c] = saturate_cast<uchar>(a * (srcImage.at<Vec3b>(i,j)[c]) + b);
            }
        }
    }
    return resultImage;
}
int main()
{
    // 图像获取及验证
    cv::Mat srcImage = cv::imread("lakeWater.jpg"); 
    if(!srcImage.data) 
       return -1;
    cv::imshow("原图", srcImage);
    //cv::waitKey(0);
    // 线性变换
    float a = 1.2;
    int b = 50;
    cv::Mat new_image  = linearTransform(srcImage, a, b);  
    cv::imshow("效果图", new_image);
    cv::waitKey(0);
    return 0;
}

3 .分段线性灰度变换

分段线性灰度变换将原图像的灰度范围划为两段或更多段,对感兴趣的目标或灰度区间进行增强,对其他不感兴趣的灰度区间进行抑制。
代码如下(示例):

#include <opencv2/opencv.hpp>  //头文件
#include <iostream>

#pragma comment(lib, "opencv_world460d.lib")  //引用引入库 

using namespace cv;  //包含cv命名空间
using namespace std;


void dividedLinearStrength(cv::Mat& matInput, cv::Mat& matOutput, float fStart, float fEnd,
	float fSout, float fEout)
{

	float fK1 = fSout / fStart;
	float fK2 = (fEout - fSout) / (fEnd - fStart);
	float fC2 = fSout - fK2 * fStart;
	float fK3 = (255.0f - fEout) / (255.0f - fEnd);
	float fC3 = 255.0f - fK3 * 255.0f;
	
	std::vector<unsigned char> loolUpTable(256);
	for (size_t m = 0; m < 256; m++)
	{
		if (m < fStart)
		{
			loolUpTable[m] = static_cast<unsigned char>(m * fK1);
		}
		else if (m > fEnd)
		{
			loolUpTable[m] = static_cast<unsigned char>(m * fK3 + fC3);
		}
		else
		{
			loolUpTable[m] = static_cast<unsigned char>(m * fK2 + fC2);
		}
	}

	matOutput = cv::Mat::zeros(matInput.rows, matInput.cols, matInput.type());

	for (size_t r = 0; r < matInput.rows; r++)
	{
		unsigned char* pInput = matInput.data + r * matInput.step[0];
		unsigned char* pOutput = matOutput.data + r * matOutput.step[0];
		for (size_t c = 0; c < matInput.cols; c++)
		{
			pOutput[c] = loolUpTable[pInput[c]];
		}
	}
}
int main()
{
	cv::Mat matSrc = cv::imread("img.jpg", cv::IMREAD_GRAYSCALE);
	cv::imshow("原始图", matSrc);
	cv::Mat matDLS;
	dividedLinearStrength(matSrc, matDLS, 72, 200, 5, 240);
	cv::imshow("分段线性拉伸", matDLS);
	cv::waitKey(0);
	return 0;
}


# 二、使用步骤
## 1.引入库
代码如下(示例):

```c
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

4.幂律变换

幂律变换主要用于图像的矫正,对灰度过高或者灰度过低的图片进行修正,增强对比度
代码如下(示例):

#include<opencv2/opencv.hpp>
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
#pragma comment(lib, "opencv_world460d.lib")  //引用引入库 
 

int main()
{
	Mat src;
	src = imread("ball.jpg");
	if(src.empty()) //检验是否成功导入数据;
	{
		cout<<"not open successed!" <<endl;
		return -1;
	}
	namedWindow("input",0);
	imshow("input",src); // 显示输入的图像src;
	cvtColor(src, src, COLOR_RGB2GRAY);
	Mat grayimg;
	grayimg.create(src.size(),src.type()); //创建一个大小类型相同的图像矩阵序列,也可以用clone()函数;
	int height = src.rows;
	int width = src.cols;
	for(int i=0;i<height;i++)
		for(int j=0;j<width;j++)
		{
			int gray = src.at< uchar>(i,j);
			grayimg.at< uchar>(i,j) = pow(gray, 0.5);//将灰度值开方;
		}
	normalize(grayimg,grayimg,0,255,NORM_MINMAX);//归一化,将数据归一到0-255之间;
	imshow("output",grayimg);//显示图像grayimg;
	waitKey(0);
	return 0;
}

2、直方图修正

图像的灰度直方图描述了图像中灰度的分布情况,能够很直观地展示出图像中各个灰度级所占的比例。灰度直方图中横坐标为各个像素点的灰度值,纵坐标表示具有各个灰度值的像素在图像中出现的次数。
在opencv中用callHist函数得到直方图数据后,就可以将其绘制出来,代码如下

#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
#include <opencv2\imgproc\types_c.h> //for CV_RGB2GRAY
using namespace cv;  //所有opencv类都在命名空间cv下
using namespace std;
#pragma comment(lib, "opencv_world460d.lib")  //引用引入库 
//绘制灰度直方图
int main(int    argc, char    *argv[])
{
	Mat src, gray;
	if(argc==1)
		src = imread("gza.jpg");  //读取工程目录下的p1.jpg图片
	else if(argc==2)
		src = imread(argv[1]);

	if (src.empty()) //判断原图是否加载成功
	{
		cout << "图像加载失败" << endl;
		return -1;
	}
	cvtColor(src, gray, CV_RGB2GRAY);   //转换为灰度图
	int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0, 256 };
	const float* ranges[] = { range };
	MatND hist;
	int channels[] = { 0 };
	//计算出灰度直方图
	calcHist(&gray, 1, channels, Mat(), // do not use mask
		hist, 1, hist_size, ranges,
		true, // the histogram is uniform
		false);
	//画出直方图
	double max_val;
	minMaxLoc(hist, 0, &max_val, 0, 0);  //定位矩阵中最小值、最大值的位置
	int scale = 2;
	int hist_height = 256;
	Mat hist_img = Mat::zeros(hist_height, bins*scale, CV_8UC3); //创建一个全0的特殊矩阵
	for (int i = 0; i < bins; i++)
	{
		float bin_val = hist.at<float>(i);
		int intensity = cvRound(bin_val*hist_height / max_val);  //要绘制的高度
		rectangle(hist_img, Point(i*scale, hist_height - 1),  //画矩形
			Point((i + 1)*scale - 1, hist_height - intensity),
			CV_RGB(255, 255, 255));
	}
	//显示原图和直方图
	imshow("原图片", src);
	imshow("灰度直方图", hist_img);
	waitKey(10000000000);
	return 0;
}

直方图的均衡化就是对图像的非线性拉伸,把给定图像的直方图分布变成均匀分布的直方图分布,使用equalizeHist函数实现直方图均衡化

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#pragma comment(lib, "opencv_world460d.lib")  //引用引入库 

using namespace cv;
using namespace std;

int main(int argc, char** argv) 
{
	Mat src = imread("img.png");
	Mat src2 = imread("img2.png");

	if (src.empty()|| src2.empty()) {
		printf("不能加载图像!\n");
		return -1;
	}
	Mat gray, gray2, dst,dst2;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	cvtColor(src2, gray2, COLOR_BGR2GRAY);
	imshow("1--原图", gray);
	imshow("11--原图", gray2);
	equalizeHist(gray, dst);
	equalizeHist(gray2, dst2);
	imshow("2--直方图均衡化", dst);
	imshow("22--直方图均衡化", dst2);

	waitKey(0);
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值