一维直方图的绘制
视频讲解如下:
在本章节中给大家演示一维直方图的绘制的绘制,当前代码同样是在毛星云的代码基础上进行扩展优化的。
当前系列所有demo下载地址:
https://github.com/GaoRenBao/OpenCv4-Demo
不同编程语言对应的OpenCv版本以及开发环境信息如下:
语言 | OpenCv版本 | IDE |
C# | OpenCvSharp4.4.8.0.20230708 | Visual Studio 2022 |
C++ | OpenCv-4.5.5-vc14_vc15 | Visual Studio 2022 |
Python | OpenCv-Python (4.6.0.66) | PyCharm Community Edition 2022.1.3 |
首先呢,我们需要准备一张测试图片。(不想下载工程的童鞋,可直接复制下面的图片和代码)

以下从左到右依次是C#、C++、Python三种版本的执行效果对比如下:

C#版本代码如下:
C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。
如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。
using OpenCvSharp;
using System;
namespace demo
{
internal class Program
{
static void Main(string[] args)
{
// 【1】载入原图并显示
Mat srcImage = Cv2.ImRead("../../../images/1283.jpg", 0);
if (srcImage.Empty())
{
Console.WriteLine("Could not open or find the image!");
return;
}
Cv2.ImShow("原图", srcImage);
//【2】定义变量
Mat dstHist = new Mat();
Rangef hueRanges = new Rangef(0, 255);
Rangef[] ranges = { hueRanges };
int[] size = { 256 };
int[] channels = { 0, 1 };
int dims = 1;
//【3】计算图像的直方图
Cv2.CalcHist(new Mat[] { srcImage },//输入的数组
channels, // 通道索引
null, // 不使用掩膜
dstHist, // 输出的目标直方图
dims, // 需要计算的直方图的维度为2
size, // 存放每个维度的直方图尺寸的数组
ranges, // 每一维数值的取值范围数组
true, // 指示直方图是否均匀的标识符,true表示均匀的直方图
false); // 累计标识符,false表示直方图在配置阶段会被清零
int scale = 1;
Mat dstImage = new Mat(size[0] * scale, size[0] * 1, MatType.CV_8U);
dstImage.SetIdentity(new Scalar(0));
//【4】获取最大值和最小值
double minValue = 0;//最小值
double maxValue = 0;//最大值
Cv2.MinMaxLoc(dstHist, out minValue, out maxValue); //查找数组和子数组的全局最小值和最大值存入maxValue中
//【5】绘制出直方图
int hpt = (int)(0.9 * size[0]);
for (int i = 0; i < 256; i++)
{
float binValue = dstHist.At<float>(i);
int realValue = (int)Math.Round(binValue * hpt / maxValue);
//绘制矩形
int a = size[0] - realValue;
int b = size[0] - 1;
int min = a > b ? b : a;
int max = a > b ? a : b;
Cv2.Rectangle(dstImage, new Point(i * scale, min),
new Point((i + 1) * scale - 1, max),
new Scalar(255, 255, 255));
}
Cv2.ImShow("一维直方图", dstImage);
Cv2.WaitKey(0);
}
}
}
C++版本代码如下:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
//【1】载入原图并显示
Mat srcImage = imread("../images/1283.jpg", 0);
imshow("原图", srcImage);
if (!srcImage.data) { cout << "fail to load image" << endl; return 0; }
//【2】定义变量
MatND dstHist; // 在cv中用CvHistogram *hist = cvCreateHist
int dims = 1;
float hranges[] = { 0, 255 };
const float* ranges[] = { hranges }; // 这里需要为const类型
int size = 256;
int channels = 0;
//【3】计算图像的直方图
calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges); // cv 中是cvCalcHist
int scale = 1;
Mat dstImage(size * scale, size, CV_8U, Scalar(0));
//【4】获取最大值和最小值
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); // 在cv中用的是cvGetMinMaxHistValue
//【5】绘制出直方图
int hpt = saturate_cast<int>(0.9 * size);
for (int i = 0; i < 256; i++)
{
float binValue = dstHist.at<float>(i); // 注意hist中是float类型 而在OpenCV1.0版中用cvQueryHistValue_1D
int realValue = saturate_cast<int>(binValue * hpt / maxValue);
rectangle(dstImage, Point(i * scale, size - 1), Point((i + 1) * scale - 1, size - realValue), Scalar(255));
}
imshow("一维直方图", dstImage);
waitKey(0);
return 0;
}
Python版本代码如下:
import cv2
import numpy as np
import random
#【1】载入原图并显示
srcImage=cv2.imread('../images/1283.jpg', 0)
cv2.imshow('srcImage', srcImage)
#【2】定义变量
size = [256]
#【3】计算图像的直方图
dstHist = cv2.calcHist([srcImage], [0], None, size, [0, 255])
scale = 1
dstImage = np.zeros((size[0] * scale, size[0], 3), np.uint8)
#【4】获取最大值和最小值
maxValue=cv2.minMaxLoc(dstHist)
#【5】绘制出直方图
hpt = 0.9 * size[0];
for i in range(256):
binValue = dstHist[i] # 直方图组距的值
realValue = round(binValue[0] * hpt / maxValue[1])
# 绘制矩形
cv2.rectangle(dstImage, (i * scale, size[0] - 1),
((i + 1) * scale - 1, size[0] - realValue), (255,255,255))
# 显示效果图
cv2.imshow('dstImage', dstImage)
cv2.waitKey(0)
在Python版本中,我们还可以使用matplotlib库进行直方图的绘制。
参考来源:OpenCV-Python-Tutorial-中文版.pdf(P126 绘制直方图)
在线预览
执行效果如下:

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('../images/1283.jpg', 0)
# img.ravel() 将图像转成一维数组
plt.hist(img.ravel(), 256, [0, 256])
plt.show()