Отображение значений пикселей гистограммы из изображения PGM (p5) с использованием Pure C без какой-либо библиотеки обработки изображений - PullRequest
0 голосов
/ 17 сентября 2011

Этот вопрос является сложным, чтобы лучше понять обработку изображений с использованием чистого языка C. Я сделал простую программу для чтения недвоичного файла PGM с использованием языка C, скомпилированного с GCC. Теперь это становится проблемой, когда я пытаюсь прочитать двоичный файл PGM. Этот двоичный файл PGM может быть получен путем преобразования JPG в PGM с использованием IrvanView .

ПРИМЕЧАНИЕ: Пожалуйста, не отвечайте ни на какую библиотеку обработки изображений (например, OpenCV).

Мой текущий код:

#include    <stdio.h> 
#include    <stdlib.h>
#define WIDTH 1024  
#define HEIGHT 768
#define READ_IMAGE_NAME "MY_PGM_FILE_NAME.pgm"

void print_histogram_table(int *histog);

main() {
  FILE *fp;

  int i,j, height= HEIGHT, width=WIDTH;
  char line[100];

  // Color depth is 255. 
  unsigned char pixel_value;

  fp = fopen(READ_IMAGE_NAME,"r");

  // get the first four lines.
  fgets (line,100,fp); 
  fgets (line,100,fp);
  fgets (line,100,fp);
  fgets (line,100,fp);

  // Histogram helper
  int histo[65536];
  int x;
  for ( x =0; x < 65536; x++) {    
        histo[x] = 0;
  }

  for(j=0;j<height;j++) {
     for(i=0;i<width;i++) {
         fread(&pixel_value, sizeof(unsigned char), 1, fp);
         // Turn on the code below, if you want to check color on specific row and column.
//             printf("row num. %d column num. %d    pixel value=%d\n",j,i,pixel_value);  

       histo[pixel_value]++;
     }
  }

  // Make histogram
  print_histogram_table(histo);

  fclose(fp);       
  getch();
}

void print_histogram_table(int *histog)
{
  int x; 
  for (x= 0; x < 255; x++) {
     if ( histog[x] != 0)
        printf("Color number %d count %d\n", x, histog[x]); 
  }
}

Я прочитал несколько страниц, связанных с моей проблемой [ Как читать файл формата .PGM? ], но я не могу найти четкого и простого ответа. Я прошу прощения за любую ошибку в моем коде. Любые предложения и критика в отношении моего кода будут оценены.

Мой скрипт выше не может отображать правильную цветовую гистограмму, потому что если вы думаете рационально, вы можете получить цвет пикселя выше 100 (не только ниже 100). Итак, главный вопрос Как решить эту проблему?

РЕДАКТИРОВАТЬ I

РЕДАКТИРОВАТЬ II

Ответы [ 3 ]

1 голос
/ 17 сентября 2011

Мой скрипт выше не может отображать правильную цветовую гистограмму, потому что, если вы думаете рационально, вы можете получить цвет пикселя выше 100 (не только ниже 100).Итак, главный вопрос: как решить эту проблему?

Я предполагаю, что вы имеете в виду:

В настоящий момент при запуске этой программы на связанном изображении отображается только- ноль записей гистограммы для значений пикселей ниже 100. Мне известно хотя бы одно значение пикселей на изображении выше 100, поэтому в моем коде есть ошибка.Может кто-нибудь помочь мне выяснить, почему это происходит?

Я предлагаю вам перефразировать ваш вопрос, чтобы прояснить это.

Код выглядит внешне хорошо, если вы только хотите, чтобы онработать над изображением, с которым вы связаны.Тем не менее, есть много мелких ошибок, которые могут сложиться.Вот несколько советов:

Размер гистограммы

Во-первых, вы не можете распечатать всю свою гистограмму.Рассмотрите возможность передачи размера гистограммы функции, которая печатает гистограмму.Более того, даже если размеры совпадают (оба 256), у вас все равно будет ошибка.Вы никогда не печатаете 256-е значение.

int histo[65536];
// ...
print_histogram_table(histo);
// ...
void print_histogram_table(int *histog)
{
    int x; 
    for (x= 0; x < 255; x++) {
       if ( histog[x] != 0)
          printf("Color number %d count %d\n", x, histog[x]); 
}

Двоичный ввод / вывод

При открытии двоичных файлов необходимо указывать «двоичный» ввод / вывод.В UNIX это традиционно не имеет значения, потому что это режим по умолчанию.Однако в Windows (я предполагаю, что вы используете Windows, так как вы используете Irfan View), вам нужно явно указать, что вы хотите двоичный ввод / вывод.

Это распространенная ошибка при работе с двоичными файламив первый раз.По сути, как только вызов fread() перехватывает байт EOF, он прекратит чтение файла и вы получите значения мусора для всех последующих операций чтения (возможно, копий последнего действительного байта), чтоозначает, что вы на самом деле не читаете все свое изображение.

fp = fopen(READ_IMAGE_NAME,"r");
// change to:
fp = fopen(READ_IMAGE_NAME,"rb");

Другие незначительные проблемы

Существует множество вещей, которые не обрабатываются вашим кодом:

  1. PNMфайлы могут иметь комментарии в начале файла
  2. Строки могут содержать более 100 символов.
  3. Размер изображения не является принудительным 1024x768
  4. Это не слишком полезно для жесткого кодирования именифайла в программе, даже для простого тестирования вашего кода.
  5. Если вы на самом деле получаете изображение в градациях серого 16 бит на пиксель, ваша гистограмма достаточно велика, но вы должны читать 2-байтовые значения.
1 голос
/ 17 сентября 2011

И ... в чем вопрос?Ваш код выглядит почти отлично для чтения двоичного PGM (P5?), Он просто пропускает проверку новой строки для каждой строки данных пикселей (согласно статье в Википедии, и ASCII, и двоичный формат имеют новые строки в конце данных каждого пикселястрока).

Некоторые комментарии:

  • Не указывайте ширину и высоту жестко, вместо этого следует использовать информацию из заголовка
  • Проверьте магическое число, бросьте/ вернуть ошибку, если это не P5 (или обрабатывать это правильно)
  • В файле могут быть комментарии к строкам, считайте, что
0 голосов
/ 17 сентября 2011

Несколько замечаний о вашей программе:

  • Вы должны прочитать заголовок, а не жестко задавать ширину, высоту и значение максимального пикселя.
  • гораздо эффективнее загрузить всеизображение в память и выполнение обработки из памяти
  • Файлы PGM являются двоичными, вы должны использовать «rb» в fopen (в случае, если вы когда-либо запускаете это в Windows, где двоичные файлы отличаются от текстовых)
  • в вашей функции печати гистограммы отсутствует последний пиксель (255 - это допустимое значение пикселя)
  • не уверен, почему ваш массив гистограмм переходит на 64K, вы планируете также поддерживать 16-битные PGM?*
  • у вас должна быть обработка ошибок, чтобы избежать сбоев или другого непредвиденного поведения

Ниже приведена улучшенная версия вашей программы с указанными выше пунктами.Надеюсь, это поможет.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[])
{
    char line[100];
    int width, height, maxval;
    unsigned char* image;
    unsigned int* histo;
    int i;
    FILE *fd;

    fd = fopen(argv[1], "rb");
    if (fd == NULL) {
        printf("could not open image file\n");
        exit(1);
    }

    // magic number
    fgets(line, sizeof(line), fd);
    if (strcmp(line, "P5\n") != 0) {
        printf("image is not in PGM format!\n");
        fclose(fd);
        exit(1);
    }

    // skip comment
    fgets(line, sizeof(line), fd);

    // read header
    if (fscanf(fd, "%d %d %d\n", &width, &height, &maxval) != 3) {
        printf("invalid header\n");
        fclose(fd);
        exit(1);
    }
    if (maxval > 255) {
        printf("sorry, only 8-bit PGMs are supported at this time!\n");
        fclose(fd);
        exit(1);
    }

    printf("width: %d\nheight: %d\nmaxval: %d\n", width, height, maxval);

    // read image data
    image = malloc(width * height);
    if (fread(image, sizeof(unsigned char), width * height, fd) != width * height) {
        printf("could not read image\n");
        fclose(fd);
        exit(1);
    }
    fclose(fd);

    // compute histogram
    histo = (int*)calloc(maxval+1, sizeof(int));
    for (i = 0; i < width * height; i++)
        histo[image[i]]++;

    // print histogram
    for (i = 0; i <= maxval; i++)
        printf("Color number %d count %d\n", i, histo[i]);

    // release memory
    free(image);
    free(histo);
}
...