C++ Super detallado 14Bit, 16Bit, 24Bit, 32Bit imagen histograma estadísticas y pantalla de dibujo, código manual

C++ OpenCv proporciona la función calcHist(), que puede ayudarnos convenientemente a contar el histograma de una imagen de 8 bits, pero no es aplicable a imágenes de bits altos como 10 bits, 12 bits, 14 bits, 16 bits, 24 bits, 32 bits, etc., y no se puede contar En este momento, necesitamos nuestro propio código escrito a mano para contar el histograma de imágenes de alto nivel. Investigué el código para contar imágenes de 16 bits sobre la base de contar el histograma de imágenes de 8 bits a mano. Para el código de contar el histograma de imágenes de 8 bits a mano, consulte mi artículo anterior, que tiene una explicación detallada. El enlace es: Agregar descripción del enlace

La imagen original de 16 bits procesada en el código se muestra a continuación. Si desea probar, puede descargarla y verla usted mismo. Nota: dado que la imagen proporcionada la subo a la página web, se puede convertir a una que no sea de 16 bits imagen por la página web Puede usar su propia imagen de 16 bits para realizar pruebas.
inserte la descripción de la imagen aquí
El código para contar a mano el histograma de imágenes de 16 bits es el siguiente:


#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>

using namespace std;
using namespace cv;


int main()
{
	
	Mat image = imread("Images/16bit/16bit_3M_whq/3M_Lj(7).png", -1);          //输入16Bit图像
	

	Mat histogram = Mat::zeros(Size(16384, 1), CV_32SC1);    	 //注意,Size对应的是x和y,也就是第一个元数是矩阵的列数,这里表示的是创建一个16384列,1行的画布
	
	int rows = image.rows;   	 //输入图像的行数
	int cols = image.cols;		 //输入图像的列数

	for (int i = 0; i<rows; i++)
	{
		for (int j = 0; j<cols; j++)
		{
			int index = int(image.at<ushort>(i, j));	//获取每个点的像素值
			histogram.at<int>(0, index) += 1;			//获取了一个像素值,在相应的位置上加1
		}
	}

	//开始直观的显示直方图——绘制直方图  
	//首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像,3通道图像画直方图的时候就可以画彩色的直方图了
	Mat drawImage1 = Mat::zeros(Size(1451,1000), CV_8UC3);   //这个画布的创建是为了最后画直方图,大小为1451列,1000行,这里可以根据自己的需求改动画布大小

	//因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制  
	//先用 minMaxLoc函数来得到计算直方图后的像素的最大个数  
	double g_dHistMaxValue;    //最大的像素值数目
	minMaxLoc(histogram, 0, &g_dHistMaxValue, 0, 0);
	cout << "像素点个数最大值:g_dHistMaxValue = " << g_dHistMaxValue << endl;
	cout << "histogram = " << histogram << endl;
	//minMaxLoc(hist, &minValue, &maxValue, 0, 0);//找到全局最小、最大的像素值数目
	//将像素的个数整合到 图像的最大范围内  
	//遍历直方图得到的数据  

	//创建下面这个画布是了只提取有灰度值的部分,因为16Bit图像的灰度范围是0-16383,太大了,如果将直方图统计后全部画在一个画布上,由于我们的电脑显示器显示不了那么大,就会都是黑的,看不到最下面的统计结果,所有创建temporary来保存只有灰度值的部分
	Mat temporary = Mat::zeros(Size(1451, 1), CV_32SC1);   //申请一个1451列,1行的黑色画布   这里为什么是1451,是因为我提供的16Bit图像的有灰度的这段,跨度大概在1451左右,这里大家可以根据自己的16Bit图像自行设置
	int j = 0;

	for (int i = 6650; i < 8101; i++)      //为什么i从6650开始,结束是8101,是因为我提供的这张16Bit图像,最大灰度值是7954,最小灰度值是6701,所以我这里设置了刚好是有灰度值张部分,其他全是0的部分就舍弃了。这里的取值范围,大家先统计统一下16Bit图像的最大值和最小值后自行设置。
	{
		int value = cvRound(histogram.at<int>(0, i) * 16384 * 0.06 / g_dHistMaxValue);   //这里公式中乘的0.06是为了使显示的直方图更低更好看一些,可以适当调整此值,自己看着舒服
		//cout << "value = " << value << endl;
		temporary.at<int>(0, j) = value;     //将有值的部分区间,全都保存到temporary中
		j++;
	}
	cout << "temporary = " << temporary;

	//下面是将保存了值的temporary绘画出来
	for (int i = 0; i < 1351; i++)
	{
		int temporary_value = temporary.at<int>(0, i);

		//line(drawImage1, Point(i, drawImage1.rows - 1), Point(i, drawImage1.rows - 1 - temporary_value), Scalar(255, 255, 0));   //用线条的方式绘画直方图
		rectangle(drawImage1, Point(i, drawImage1.rows - 1), Point(i+1, drawImage1.rows - 1 - temporary_value), Scalar(255, 255, 0));  //用矩形的方式绘画直方图
	}

	imshow("【16Bit图像直方图】", drawImage1);
	imshow("image", image);

	waitKey();
	return 0;
}

El resultado de ejecutar el código anterior es el siguiente:
los siguientes son los datos almacenados en el histograma, hay muchos 0 y el rango de valor gris útil es solo una pequeña parte: los
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
siguientes son los datos almacenados en el temporal y el sobre el rango de valores de gris útil Extráigalo y guarde solo el intervalo de escala de grises útil:
inserte la descripción de la imagen aquí
El siguiente es el histograma de la imagen de 16 bits después de las estadísticas:
inserte la descripción de la imagen aquí
Finalmente, agregue la descripción específica de varios parámetros de función clave en el código y guarde todos para verificar, ver abajo:

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0,
 Point* maxLoc=0, InputArray mask=noArray())

找出矩阵中最大和最小的值以及他们的坐标
src – Source single-channel array. 单通道数组
minVal – Pointer to the returned minimum value. NULL is used if not required. 指向最小值的指针
maxVal – Pointer to the returned maximum value. NULL is used if not required. 指向最大值的指针
minLoc – Pointer to the returned minimum location (in 2D case). NULL is used if not required. 最小值的二维坐标
maxLoc – Pointer to the returned maximum location (in 2D case). NULL is used if not required. 最大值得二维坐标
mask – Optional mask used to select a sub-array. 掩码
void cvLine( CvArr* img,CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1,
int line_type=8, int shift=0 );

第一个参数img:要划的线所在的图像;
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8, 8 (or 0) - 8-connected line(8邻接)连接 线。4 - 4-connected line(4邻接)连接线。CV_AA - antialiased 线条。
第六个参数:坐标点的小数点位数。

Aquí también se agrega la función calcHist() en C++ OpenCv, vea a continuación:

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims,
 const int* histSize, const float** ranges, booluniform=true, bool accumulate=false )

计算直方图,统计各灰度的像素个数,其输出为多维矩阵
const Mat* images:为输入图像的指针。
int nimages:要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1。
const int* channels:图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};
IuputArray mask:是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。
OutArray hist:计算得到的直方图
int dims:得到的直方图的维数,灰度图像为1维,彩色图像为3维。
const int* histSize:直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。
const float** ranges:这是一个二维数组,用来指出每个区间的范围。后面两个参数都有默认值,uniform参数表明直方图是否等距,最后一个参数与多图像下直方图的显示与存储有关。

El proceso detallado anterior de contar el histograma de imágenes de 16 bits a través del código a mano, de manera similar, utilizando métodos estadísticos similares, puede contar los histogramas de otras imágenes de bits altos. Si mi método es útil para usted, por favor inspíreme. Me gusta, anímame, ¡gracias!

Supongo que te gusta

Origin blog.csdn.net/qq_40280673/article/details/124333518
Recomendado
Clasificación