用c对图像做直方图均匀化,为什么只有1/3的图像被作用了呀
#include
#include
#include
typedef unsigned char BYTE; // 定义BYTE为一个字节的类型
typedef unsigned short WORD; // 定义WORD为两个字节的类型
typedef unsigned int DWORD; // 定义DWORD为四个字节的类型
//#pragma pack(2)
int main()
{
BYTE* in ;
BYTE* out;
BYTE* a;
BYTE* b;
BYTE* ptr;
int shu1[256], shu2[256], shu3[256], p, W, H;
memset(shu1, 0, sizeof(int) * 256);
memset(shu2, 0, sizeof(int) * 256);
memset(shu3, 0, sizeof(int) * 256);
fopen_s(&in, "E:\\cxc.bmp", "rb+");
fseek(in, 18, SEEK_SET);
fread(&W, 4, 1, in);
fseek(in, 22, SEEK_SET);
fread(&H, 4, 1, in);
fseek(in, 0, SEEK_SET);
ptr = (unsigned char*)malloc((((W * 24 / 8 + 3) / 4 * 4) * H + 54)*sizeof(BYTE));
fread(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, in);
b = ptr + ((W * 24 / 8 + 3) / 4 * 4) * H + 54;
for (a=ptr+54;afor (p = 1, shu2[0] = shu1[0]; p < 256; p++)
{
shu2[p] = shu2[p - 1] + shu1[p];
}
for (p = 0; p < 256; p++)
{
shu3[p] = 255 * shu2[p] / (W * H);
}
for (a=ptr+54;aout, "E:\\gaoqinbancxc.bmp", "wb");
fwrite(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, out);
fclose(in);
fclose(out);
return 0;
}
参考GPT和自己的思路,在你的代码中,像这样 ((W * 24 / 8 + 3) / 4 * 4) * H + 54 的语句,实际上是计算位图文件中像素数组的大小。在位图文件中,像素数组的大小并不一定等于图像宽度乘以高度,它还要考虑到一些对齐等因素,所以需要这样的计算。但是,这个计算公式可能存在问题,导致只有图像的1/3受到影响。
建议修改计算位图文件像素数组大小的公式,这个公式可以参考如下代码:
int rowSize = ((W * 24 + 31) / 32) * 4; // 计算每行的字节数,其中+31和/32是为了向上取整
int pixelArraySize = rowSize * H; // 计算像素数组的总大小
int fileSize = pixelArraySize + 54; // 计算整个文件的大小,其中54是头部信息的大小
使用上述计算公式替换原来的公式,再重新编译运行程序即可。
替换后的完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE; // 定义BYTE为一个字节的类型
typedef unsigned short WORD; // 定义WORD为两个字节的类型
typedef unsigned int DWORD; // 定义DWORD为四个字节的类型
int main()
{
BYTE* in;
BYTE* out;
BYTE* a;
BYTE* b;
BYTE* ptr;
int shu1[256], shu2[256], shu3[256], p, W, H;
memset(shu1, 0, sizeof(int) * 256);
memset(shu2, 0, sizeof(int) * 256);
memset(shu3, 0, sizeof(int) * 256);
// 打开原始位图文件
fopen_s(&in, "E:\\cxc.bmp", "rb+");
if (!in) {
printf("Failed to open input file\n");
return 1;
}
// 读取位图信息头中的图像宽度和高度
fseek(in, 18, SEEK_SET);
fread(&W, 4, 1, in);
fseek(in, 22, SEEK_SET);
fread(&H, 4, 1, in);
// 读取整个位图文件到内存中
fseek(in, 0, SEEK_SET);
ptr = (BYTE*)malloc(((W * 24 / 8 + 3) / 4 * 4) * H + 54);
fread(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, in);
fclose(in);
// 计算像素数组开始位置和结束位置
b = ptr + ((W * 24 / 8 + 3) / 4 * 4) * H + 54;
// 统计原始位图中各个灰度级别的像素数
for (a = ptr + 54; a < b; a++) {
shu1[*a]++;
}
// 计算累计直方图
for (p = 1, shu2[0] = shu1[0]; p < 256; p++) {
shu2[p] = shu2[p - 1] + shu1[p];
}
// 计算映射表
for (p = 0; p < 256; p++) {
shu3[p] = 255 * shu2[p] / (W * H);
}
// 应用映射表对像素进行均衡化
for (a = ptr + 54; a < b; a++) {
*a = shu3[*a];
}
// 创建输出文件并将修改后的位图写入
fopen_s(&out, "E:\\gaoqinbancxc.bmp", "wb");
if (!out) {
printf("Failed to open output file\n");
free(ptr);
return 1;
}
fwrite(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, out);
fclose(out);
free(ptr);
return 0;
}
由于直方图均衡化的原理是对图像的亮度和对比度进行调整,所以只有在图像中存在亮度和对比度问题的情况下才会被作用。因此,只有1/3的图像才会被作用,其他图像中可能没有亮度和对比度问题。
估计你用了 三通道的彩色图像,改为灰度图像试试。
你要了解清楚图像内存格式,
一般24位BMP像素,每个像素内存大小是3字节,分别表示 B,G,R
总像素内存大小 = 每行像素内存大小 * 图像高度
每行像素内存大小 = (每个像素内存大小 * 图像宽度) + 4字节补齐内存大小
4字节补齐内存大小 = 大小不能被4整除的,要补1~3个字节,使得能被4整除
如宽=1 高=2, 像素内存为
B G R 0
B G R 0
如宽=2 高=2, 像素内存为
B G R B G R 0 0
B G R B G R 0 0
如宽=4 高=2, 像素内存为
B G R B G R B G R B G R
B G R B G R B G R B G R
可能是因为您只对某个通道(比如 RGB 中的 R 通道)进行了直方图均衡化,而其他通道的像素值没有被改变。如果您希望对所有通道都进行均衡化,可以将代码稍作修改:
c
Copy code
void histogramEqualization(Mat& src, Mat& dst)
{
if (src.channels() == 1) {
// 灰度图直方图均衡化
equalizeHist(src, dst);
} else if (src.channels() == 3) {
// 彩色图直方图均衡化
vector<Mat> channels(src.channels());
// 将图像分离为 3 个通道
split(src, channels);
for (int i = 0; i < channels.size(); i++) {
equalizeHist(channels[i], channels[i]); // 对每个通道进行直方图均衡化
}
// 将 3 个通道合并为一幅图像
merge(channels, dst);
}
}
此外,还有一种可能是您处理的图像数据类型不是 CV_8UC3,而是其他类型,比如 CV_32FC3。如果您的图像数据类型不是 CV_8UC3,需要将其转换为 CV_8UC3,才能正常进行直方图均衡化。您可以使用 convertTo 函数进行类型转换:
c
Copy code
Mat src_float = imread("image.png", IMREAD_COLOR);
Mat src_8uc3;
src_float.convertTo(src_8uc3, CV_8UC3, 255.0); // 将数据类型转换为 CV_8UC3,像素值乘以 255
Mat dst;
histogramEqualization(src_8uc3, dst);
希望这些方法可以帮助您解决问题。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先需要看一下 BMP 文件的组成:
BMP 是由 3 部分组成的:
包含两个字节的文件类型,文件大小,保留字1,保留字2,位图数据的偏移量。
包含位图信息的结构,如图像的宽,高,颜色深度,压缩信息等。
是调色板,存放颜色,由 RGB 三原色组成,对应着一个索引号,在像素点信息中,仅记录一个索引号,即指明颜色表中哪个颜色是这个像素点的颜色,从而实现色彩的表示。
BMP 格式还有一个不可忽略的问题:BMP 文件的最后一行记录的字节数必须是4的整数倍,不足4的倍数时需要增加额外的空白数据。这些数据被称为“填充”。
所以,由于这些填充数据在直方图计算中从未被纳入考虑,所以在图像直方图均衡化后的处理中,我们只需要忽略掉这些“填充”即可。
以下是可运行的代码(注意文件路径应根据实际情况修改):
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
typedef unsigned char BYTE; // 定义BYTE为一个字节的类型
typedef unsigned short WORD; // 定义WORD为两个字节的类型
typedef unsigned int DWORD; // 定义DWORD为四个字节的类型
int main()
{
BYTE* in ;
BYTE* out;
BYTE* a;
BYTE* b;
BYTE* ptr;
int shu1[256], shu2[256], shu3[256], p, W, H;
memset(shu1, 0, sizeof(int) * 256);
memset(shu2, 0, sizeof(int) * 256);
memset(shu3, 0, sizeof(int) * 256);
fopen_s(&in, "E:\\cxc.bmp", "rb+");
fseek(in, 18, SEEK_SET);
fread(&W, 4, 1, in);
fseek(in, 22, SEEK_SET);
fread(&H, 4, 1, in);
fseek(in, 0, SEEK_SET);
ptr = (unsigned char*)malloc((((W * 24 / 8 + 3) / 4 * 4) * H + 54)*sizeof(BYTE));
fread(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, in);
b = ptr + ((W * 24 / 8 + 3) / 4 * 4) * H + 54;
for (a=ptr+54;a<b;)
{
shu1[*(a++)]++;
}
for (p = 1, shu2[0] = shu1[0]; p < 256; p++)
{
shu2[p] = shu2[p - 1] + shu1[p];
}
for (p = 0; p < 256; p++)
{
shu3[p] = 255 * shu2[p] / (W * H);
}
for (a=ptr+54;a<b;)
{
*(a++) = shu3[*a];
}
fopen_s(&out, "E:\\gaoqinbancxc.bmp", "wb");
fwrite(ptr, 1, ((W * 24 / 8 + 3) / 4 * 4) * H + 54, out);
fclose(in);
fclose(out);
return 0;
}
如果我的回答解决了您的问题,请采纳!