c - 如何获取bmp中出现频率最高的像素

标签 c colors rgb pixel bmp

作为确定“图像基色”的函数,我正在尝试实现以下代码:

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 结构,带有图像的基色。然而..它返回不正确的颜色。我做错了什么?

最佳答案

正如其他人已经指出的那样,有几个问题,最重要的一个是 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;
}

关于c - 如何获取bmp中出现频率最高的像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26546522/

相关文章:

java - 在JAVA中,将图像的RGB值转换为二进制值的最快方法是什么?

c - 将数组称为指针

perl - 如何使用 printf 和 Perl 的 Term::ANSIColor 获得彩色输出?

java - 在 Android 应用程序中使用 XML 更改进度条颜色

Iphone 我正在使用 cocos2d 并且需要 Sprite 上像素的 rgba 值

python - 将图像中颜色的不同深浅转换为一种颜色

c - pthread_cond_timedwait()

C 或 C++ 中的 Java ByteArray 等价物

在 C 中编码 : efficiency of temporary local variables

java - 在Java中,如何更改按钮的颜色,等待几秒钟,然后再次更改?