图像处理:直方图——直方图均衡化 OpenCV v4.8.0

本文介绍了图像直方图的概念及其在OpenCV中的应用,通过cv::equalizeHist函数实现直方图均衡化以改善图像对比度。展示了如何使用C++、Java和Python代码进行图像预处理并显示结果。
摘要由CSDN通过智能技术生成

上一个教程仿射变换

下一个教程直方图计算

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,你将学习

  • 什么是图像直方图以及它的用处
  • 使用 OpenCV 函数 cv::equalizeHist 均衡图像直方图

理论

什么是图像直方图?

  • 它是图像强度分布的图形表示。
  • 它量化了每个强度值的像素数量。
    在这里插入图片描述

什么是直方图均衡化?

  • 这是一种改善图像对比度的方法,目的是拉大强度范围(另见维基百科相应词条)。
  • 从上图中可以更清楚地看到,像素似乎集中在现有强度范围的中间位置。直方图均衡化的作用就是拉伸这个范围。请看下图: 绿色的圆圈表示强度不足的区域。应用均衡化后,我们得到的直方图就像中间的图一样。得到的图像如右图所示。
    在这里插入图片描述

它是如何工作的?

  • 均衡化意味着将一种分布(给定的直方图)映射到另一种分布(一种更广泛、更均匀的强度值分布),从而使强度值遍布整个范围。
  • 要实现均衡化效果,重映射应该是累积分布函数(cdf)(更多详情,请参阅学习 OpenCV)。对于直方图 H(i),其累积分布 H′(i)为

H ′ ( i ) = ∑ 0 ≤ j < i H ( j ) H'\left( i \right) =\sum_{0\le j<i}^{}{H\left( j \right)} H(i)=0j<iH(j)

要将其用作重映射函数,我们必须对 H′(i)进行归一化处理,使其最大值为 255(或图像强度的最大值)。根据上面的例子,累积函数为

在这里插入图片描述

  • 最后,我们使用一个简单的重映射过程来获取均衡化图像的强度值:

e q u a l i z e d ( x , y ) = H ′ ( s r c ( x , y ) ) equalized\left( x,y \right) =H'\left( src\left( x,y \right) \right) equalized(x,y)=H(src(x,y))

代码

  • 这个程序要做什么?
    • 加载图像
    • 将原始图像转换为灰度图像
    • 使用 OpenCV 函数 cv::equalizeHist 均衡直方图
    • 在一个窗口中显示源图像和均衡化后的图像。

C++

  • 可下载代码: 点击此处
  • 代码一览
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
 CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
 Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
 if( src.empty() )
 {
 cout << "Could not open or find the image!\n" << endl;
 cout << "Usage: " << argv[0] << " <Input image>" << endl;
 return -1;
 }
 cvtColor( src, src, COLOR_BGR2GRAY );
 Mat dst;
 equalizeHist( src, dst );
 imshow( "Source image", src );
 imshow( "Equalized Image", dst );
 waitKey();
 return 0;
}

Java

  • 可下载代码: 点击此处
  • 代码一览
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class EqualizeHist {
 public void run(String[] args) {
 String filename = args.length > 0 ? args[0] : "../data/lena.jpg";
 Mat src = Imgcodecs.imread(filename);
 if (src.empty()) {
 System.err.println("Cannot read image: " + filename);
 System.exit(0);
 }
 Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
 Mat dst = new Mat();
 Imgproc.equalizeHist( src, dst );
 HighGui.imshow( "Source image", src );
 HighGui.imshow( "Equalized Image", dst );
 HighGui.waitKey(0);
 System.exit(0);
 }
}
public class EqualizeHistDemo {
 public static void main(String[] args) {
 // Load the native OpenCV library
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
 new EqualizeHist().run(args);
 }
}

Python

  • 可下载代码: 点击此处
  • 代码一览
from __future__ import print_function
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='Code for Histogram Equalization tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
 print('Could not open or find the image:', args.input)
 exit(0)
src = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
dst = cv.equalizeHist(src)
cv.imshow('Source image', src)
cv.imshow('Equalized Image', dst)
cv.waitKey()

说明

  • 加载源图像:
    C++
 CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
 Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
 if( src.empty() )
 {
 cout << "Could not open or find the image!\n" << endl;
 cout << "Usage: " << argv[0] << " <Input image>" << endl;
 return -1;
 }

Java

 String filename = args.length > 0 ? args[0] : "../data/lena.jpg";
 Mat src = Imgcodecs.imread(filename);
 if (src.empty()) {
 System.err.println("Cannot read image: " + filename);
 System.exit(0);
 }

Python

parser = argparse.ArgumentParser(description='Code for Histogram Equalization tutorial.')
parser.add_argument('--input', help='Path to input image.', default='lena.jpg')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
 print('Could not open or find the image:', args.input)
 exit(0)
  • 转换为灰度图像
    C++
 cvtColor( src, src, COLOR_BGR2GRAY );

Java

 Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);

Python

src = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

-使用函数 cv::equalizeHist 应用直方图均衡化:
C++

 Mat dst;
 equalizeHist( src, dst );

Java

 Mat dst = new Mat();
 Imgproc.equalizeHist( src, dst );

Python

dst = cv.equalizeHist(src)

不难看出,参数只有原始图像和输出(均衡化)图像。

  • 显示两幅图像(原始图像和均衡化图像):
    C++
 imshow( "Source image", src );
 imshow( "Equalized Image", dst );

Java

 HighGui.imshow( "Source image", src );
 HighGui.imshow( "Equalized Image", dst );

Python

cv.imshow('Source image', src)
cv.imshow('Equalized Image', dst)
  • 等待用户退出程序
    C++
 waitKey();

Java

 HighGui.waitKey(0);

Python

cv.waitKey()

结果

  1. 为了更好地了解均衡化的结果,让我们引入一张对比度不大的图像,例如

在这里插入图片描述

顺便说一下,它的直方图是这样的:

在这里插入图片描述

请注意,像素都集中在直方图的中心。

  1. 在使用我们的程序进行均衡处理后,我们得到了这样的结果:

在这里插入图片描述

这幅图像的对比度明显增加了。看看它的新直方图

在这里插入图片描述

请注意,像素数量在强度范围内的分布更均匀了。

注意
您是否想知道我们是如何绘制上述直方图的?请查看接下来的教程!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值