作为确定"图像的基色的功能"我试图实现以下代码:
typedef unsigned long dword;
typedef unsigned short word;
typedef unsigned char BYTE;
typedef struct
{
BYTE R;
BYTE G;
BYTE B;
} RGB;
RGB
bitfox_get_primecolor_direct
(char *FILE_NAME)
{
RGB primecolor;
BYTE rgb[3];
dword *counts;
dword max_count = 0;
FILE* fp = fopen("sample.bmp", "rb");
counts = calloc(pow(256, 3), sizeof(*counts));
fseek(fp, 54, SEEK_SET);
while (fread (rgb, sizeof(BYTE), 3, fp) == 1)
{
dword idx = (((dword)rgb[0]) << 16) | (((dword)rgb[1]) << 8) | (dword)rgb[2];
if (++counts[idx] > max_count) max_count = idx;
}
primecolor.R = (rgb[max_count] >> 16) & 0xFF;
primecolor.G = (rgb[max_count] >> 8) & 0xFF;
primecolor.B = rgb[max_count] & 0xFF;
free(counts);
fclose(fp);
return primecolor;
}
它应该是一个快速的算法(当涉及到RAM时不是很节俭)来返回RGB结构,具有图像的基色。但是..它返回不正确的颜色。我做错了什么?
答案 0 :(得分:4)
正如其他人已经指出的那样,有几个问题,最重要的问题是max_count
的索引。您可以使max_count
成为索引,然后使用构造索引时使用的反向逻辑从该索引派生颜色。这就是Steffen和user694733的答案的工作原理。
您还可以将max_count
作为计数,并在找到新的最大计数时指定primecolor
。这可以节省您的反向计算。
这是一个与填充有关的潜在问题。 BMP格式按行存储其数据,但每行中的字节数必须是4的倍数。在您的情况下,图像宽度为262像素。每行长786个字节,因此必须填充到788.如果要考虑填充,则必须知道图像的宽度。
另一个混淆的原因是您将参数FILE_NAME
传递给您的函数,但始终打开"sample.bmp"
,因此您可能无法获得所需内容。
此外,但这是一个小问题,我认为整数多维数据集pow(256, 3)
最好呈现为256 * 256 * 256
。
这是适用于我的varaint(需要更多错误检查):
RGB bitfox_get_primecolor_direct(char *FILE_NAME)
{
RGB primecolor = {0, 0, 0};
BYTE hdr[54];
dword *counts;
dword max_count = 0;
word w, h;
word i, j;
FILE* fp = fopen(FILE_NAME, "rb");
counts = calloc(256 * 256 * 256, sizeof(*counts));
// Read header to get width and height
fread(hdr, sizeof(hdr), 1, fp);
w = (hdr[19] << 8) | hdr[18];
h = (hdr[23] << 8) | hdr[22];
// Loop over pixels
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
RGB rgb;
dword idx;
if (fread(&rgb, 3, 1, fp) < 1) {
fprintf(stderr, "Unexpected end of file.\n");
exit(1);
}
idx = (rgb.R << 16) | (rgb.G << 8) | rgb.B;
if (++counts[idx] > max_count) {
max_count = counts[idx];
primecolor = rgb;
}
}
// Treat padding
j = 3 * w;
while (j++ % 4) getc(fp);
}
free(counts);
fclose(fp);
return primecolor;
}
答案 1 :(得分:2)
好的。几点:
一个是pow
功能。我发现这不符合预期。至少在我的实施上。
counts = calloc((dword)pow(256.0, 3.0), sizeof(dword));
适合我。
fread应该检查元素的数量:
fread (rgb, sizeof(BYTE), 3, fp) == 3
检查哪个值为max应该是:
if (++(counts[idx]) > counts[max_count]) {
max_count = idx;
}
最后,颜色的提取可以通过以下方式完成:
primecolor.R = max_count >> 16 & 0xFF;
primecolor.G = max_count >> 8 & 0xFF;
primecolor.B = max_count & 0xFF;
通过这些更改,它对我有用。唯一的事就是我得到了BGR。但这可能是由于形象不同......
完整代码:
#include <stdio.h>
#include <math.h>
typedef unsigned long dword;
typedef unsigned short word;
typedef unsigned char BYTE;
typedef struct
{
BYTE R;
BYTE G;
BYTE B;
} RGB;
void main (void)
{
RGB primecolor;
BYTE rgb[3];
dword *counts;
dword max_count = 0;
FILE* fp = fopen("c:/tmp/test.bmp", "rb");
counts = calloc((dword)pow(256.0, 3.0), sizeof(dword));
fseek(fp, 54, SEEK_SET);
while (fread (rgb, sizeof(BYTE), 3, fp) == 3)
{
BYTE r = rgb[0];
BYTE g = rgb[1];
BYTE b = rgb[2];
dword idx = (((dword)rgb[0]) << 16) | (((dword)rgb[1]) << 8) | (dword)rgb[2];
if (++(counts[idx]) > counts[max_count]) {
max_count = idx;
}
}
primecolor.R = max_count >> 16 & 0xFF;
primecolor.G = max_count >> 8 & 0xFF;
primecolor.B = max_count & 0xFF;
free(counts);
fclose(fp);
printf("%d %d %d ",primecolor.R,primecolor.G,primecolor.B);
}
这打印出229 20 35用于使用填充颜色(RGB)的gimp创建的图像:35,20,229。
答案 2 :(得分:1)
除了注释中提到的问题(不检查返回值,无效fread
返回值检查,可能假设文件格式不正确...),max_count
存在问题:
if (++counts[idx] > max_count) max_count = idx;
在条件中,您认为max_count
是一个计数器。但是,在分配中,您将max_count
视为索引值(相当于颜色)。应该是哪一个?
rgb[max_count]
也没有意义。您再次将max_count
视为索引(再次为颜色)。 rgb
应该是最新的读取颜色,因此根本不应该使用它。