LINUX.ORG.RU

Изменение цвета пикселей в простой программе по копированию bmp файла

 


0

2

Добрый день!

Пожалуйста, посмотрите программу, которая копирует один bmp файл в другой bmp файл и при этом меняет пиксели, которые были красными на белые; также она должна выполнить еще одну функцию. Программа была написана ребятами, которые преподают курс по компьютерной граммотности в Америке. Я попробовала дописать небольшой кусок кода, который должен был поменять на синий цвет пискелей, в которых красный цвет не равен 0хff (этот кусок я выделю в программе комментарием на русском языке). Однако мой кусок кода меняет все изображение, делая его полностью заполненным бело-синими пикселями, а не только нужные пиксели. Пожалуйста, помогите понять, почему так происходит. Цель: 1) поменять все пиксели со значеним красного цвета 0xff на белые, то есть ffffff; 2) поменять цвет пикселей, в которых красный *не равен* 0xff (например, ffff83) на синий цвет.

/*
* Copies a BMP piece by piece.
 */
       
#include <stdio.h>
#include <stdlib.h>

#include "bmp.h"

int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 3)
    {
        printf("Usage: ./copy infile outfile\n");
        return 1;
    }

    // remember filenames
    char* infile = argv[1];
    char* outfile = argv[2];

    // open input file 
    FILE* inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        printf("Could not open %s.\n", infile);
        return 2;
    }

    // open output file
    FILE* outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 3;
    }

    // read infile's BITMAPFILEHEADER
    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || 
        bi.biBitCount != 24 || bi.biCompression != 0)
    {
        fclose(outptr);
        fclose(inptr);
        fprintf(stderr, "Unsupported file format.\n");
        return 4;
    }

    // write outfile's BITMAPFILEHEADER
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

    // determine padding for scanlines
    int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        // iterate over pixels in scanline
        for (int j = 0; j < bi.biWidth; j++)
        {
            // temporary storage
            RGBTRIPLE triple;

            // read RGB triple from infile
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
            
            if (triple.rgbtRed == 0xff && triple.rgbtBlue == 0x00 && triple.rgbtGreen == 0x00)
            {
                triple.rgbtBlue = 0xff;
                triple.rgbtGreen = 0xff;
            }
            
            // этот кусок не работает; вместо отдельных пикселей
            заполняет всю картинку
            if (triple.rgbtRed != 0xff)
            {
                triple.rgbtRed = 0x0a;
                triple.rgbtGreen = 0x84;
            }
        
            // write RGB triple to outfile
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }

        // skip over padding, if any
        fseek(inptr, padding, SEEK_CUR);

        // then add it back (to demonstrate how)
        for (int k = 0; k < padding; k++)
        {
            fputc(0x00, outptr);
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

bmp.h

#include <stdint.h>

/**
 * Common Data Types 
 *
 * The data types in this section are essentially aliases for C/C++ 
 * primitive data types.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx.
 * See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
 */
typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

/**
 * BITMAPFILEHEADER
 *
 * The BITMAPFILEHEADER structure contains information about the type, size,
 * and layout of a file that contains a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx.
 */
typedef struct 
{ 
    WORD   bfType; 
    DWORD  bfSize; 
    WORD   bfReserved1; 
    WORD   bfReserved2; 
    DWORD  bfOffBits; 
} __attribute__((__packed__)) 
BITMAPFILEHEADER; 

/**
 * BITMAPINFOHEADER
 *
 * The BITMAPINFOHEADER structure contains information about the 
 * dimensions and color format of a DIB [device-independent bitmap].
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/dd183376(VS.85).aspx.
 */
typedef struct
{
    DWORD  biSize; 
    LONG   biWidth; 
    LONG   biHeight; 
    WORD   biPlanes; 
    WORD   biBitCount; 
    DWORD  biCompression; 
    DWORD  biSizeImage; 
    LONG   biXPelsPerMeter; 
    LONG   biYPelsPerMeter; 
    DWORD  biClrUsed; 
    DWORD  biClrImportant; 
} __attribute__((__packed__))
BITMAPINFOHEADER; 

/**
 * RGBTRIPLE
 *
 * This structure describes a color consisting of relative intensities of
 * red, green, and blue.
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
 */
typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;

Спасибо большое!


поменять все пиксели со значеним красного цвета 0xff на белые, то есть ffffff
поменять цвет пикселей, в которых красный *не равен* 0xff, на синий цвет

Согласитесь, что красная компонента может быть либо равна 0xff, либо не равна 0xff. Третьего не дано, эти два события исчерпывают вероятностное пространство. Следовательно, нет ничего странного в том, что всё изображение становится

заполненным бело-синими пикселями

Разве нет?

AITap ★★★★★ ()
Последнее исправление: AITap (всего исправлений: 1)
Ответ на: комментарий от AITap

Поменять все пиксели со значеним красного цвета 0xff на белые, то есть ffffff;

Но в коде у тебя написано другое:

if (triple.rgbtRed == 0xff && triple.rgbtBlue == 0x00 && triple.rgbtGreen == 0x00)
    {
        triple.rgbtBlue = 0xff;
        triple.rgbtGreen = 0xff;
    }
            
// этот кусок не работает; вместо отдельных пикселей заполняет всю картинку
if (triple.rgbtRed != 0xff)
    {
        triple.rgbtRed = 0x0a;
        triple.rgbtGreen = 0x84;
    }
то есть:

  1. Чисто красные пиксели (где красный = 0xFF, синий = зелёный = 0) сделать белыми.
  2. У пикселей, где красная компонента != 0xFF, сделать красный = 0x0a, а зелёный = 0x84 (а синюю компоненту не трогать).
  3. Прочие пиксели не трогать вообще.
proud_anon ★★★★★ ()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

да да, именно как Вы написали - три пункта. И вот пункт 2 не получается. С первым проблем нет вообще. Offtopic: как Вам удалось сделать новую строку для каждого пункта? У меня здесь получается писать только в одну строку весь текст. Спасибо!

Вот что я получаю при выводе 240 байтов после того, как меняю красные пиксели на белые

 $ xxd -l240 -c24 -g3 -s54 verdict_fin0.bmp
0000036: ffffff ffff88 ffff82 ffff83 ffffff ffff81 ffff83 ffff82  ........................
000004e: feff7c ffff83 ffffff ffffff ffffff ffffff ffff83 ffffff  ..|.....................
0000066: ffffff ffff83 ffff88 feff8a ffff83 feff7d ffffff ffffff  .................}......
000007e: ffffff ffff83 ffffff ffff88 ffff88 ffffff ffffff ffffff  ........................
0000096: ffff88 ffff83 ffff88 ffff83 ffff88 ffff7f feff8a ffffff  ........................
00000ae: ffffff ffffff ffff88 ffffff ffff8c ffffff ffff88 feff8a  ........................
00000c6: ffffff ffffff ffff88 ffffff feff8a ffffff feff8e ffff88  ........................
00000de: ffffff ffffff ffffff ffffff ffff88 ffffff ffffff ffff7b  .......................{
00000f6: feff82 fefe82 ffffff ffffff ffffff ffff83 ffffff ffffff  ........................
000010e: ffffff ffffff ffff88 ffffff ffffff ffff88 ffff88 ffffff  ........................
После этого я пытаюсь сделать пункт 2, но почему-то мой код не работает как я хотела и получается что именно вся картинка заполняется синим. Судя по всему я меняю не те пиксели, но тогда я не вижу какие поменять, чтобы достигнуть желаемого эффекта, а именно «поднять» синий цвет только изображения, а не всей картинки.
0000036: ffffff ff840a ff840a ff840a ffffff ff840a ff840a ff840a  ........................
000004e: fe840a ff840a ffffff ffffff ffffff ffffff ff840a ffffff  ........................
0000066: ffffff ff840a ff840a fe840a ff840a fe840a ffffff ffffff  ........................
000007e: ffffff ff840a ffffff ff840a ff840a ffffff ffffff ffffff  ........................
0000096: ff840a ff840a ff840a ff840a ff840a ff840a fe840a ffffff  ........................
00000ae: ffffff ffffff ff840a ffffff ff840a ffffff ff840a fe840a  ........................
00000c6: ffffff ffffff ff840a ffffff fe840a ffffff fe840a ff840a  ........................
00000de: ffffff ffffff ffffff ffffff ff840a ffffff ffffff ff840a  ........................
00000f6: fe840a fe840a ffffff ffffff ffffff ff840a ffffff ffffff  ........................
000010e: ffffff ffffff ff840a ffffff ffffff ff840a ff840a ffffff  ........................

Ducol ()

У меня одного сложилось впечатление, что все, работающие с типом "BMP" — дебилы?

На этот быдлокод же смотреть больно!

ТС, не будь идиотом, пользуйся хотя бы png, нафиг тебе этот идиотский битмап? Ну, если жать не хочешь, используй xbm или pnm…

anonymous ()
Ответ на: комментарий от Ducol

какое отношение

«поднять» синий цвет только изображения, а не всей картинки

вообще имеет к

поменять на синий цвет пискелей, в которых красный цвет не равен 0хff?

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

и это, заметь, никакого кода смотреть и писать не надо. ошибка еще в условии.

я не вижу какие поменять, чтобы достигнуть желаемого эффекта, а именно «поднять» синий цвет

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

насколько именно гасить каждую из них — это уже надо выводить из luminosity function, ну да это уже шут с ним, потом.

только изображения, а не всей картинки.

что такое вообще «изображение», которое «не вся картинка»? телепаты, где вы?

t184256 ★★★★★ ()
Ответ на: комментарий от Ducol

Offtopic: как Вам удалось сделать новую строку для каждого пункта? У меня здесь получается писать только в одну строку весь текст.

[list=1][*]П. 1
[*]П. 2
[*]П. 3[/list]


После этого я пытаюсь сделать пункт 2, но почему-то мой код не работает как я хотела

Если файл сверху прогнать через этот код, то получится файл снизу. Как Вы написали, так он и работает.

Только ведь программа сразу делает и преобразование красного в белый, и второе преобразование, зачем вы заменили красный цвет белым отдельно?

Судя по всему я меняю не те пиксели, но тогда я не вижу какие поменять, чтобы достигнуть желаемого эффекта, а именно «поднять» синий цвет только изображения, а не всей картинки.

Совершенно непонятно, что Вы хотите сказать.

proud_anon ★★★★★ ()
Ответ на: комментарий от proud_anon
  1. Спасибо за помощь в написании )
  2. Я действительно пока очень плохо формулирую (учусь, но на русском
  3. мне сложнее формулировать, потому что изучаю на английском).
  4. Суть задания: дана картинка, на которой за красными пикселями
  5. есть изображение лица человека. Задача вначале убрать все красные
  6. заменив их на белые. В результате становится видно лицо. Но пиксели
  7. голубые, поэтому чтобы понять точнее кто изображен, мне нужно
  8. только это пискели лица сделать темнее. Это я и пыталась сделать
  9. исходя из информации показанной командой xxd. Я на совсем начальном
  10. уровне, поэтому пока действую по выданным инструкциям и пытаюсь
  11. как-то разобраться.
if (triple.rgbtRed != 0xff)
    {
        triple.rgbtRed = 0x0a;
        triple.rgbtGreen = 0x84;
    }
  • исходя из того, что я увидела после введения xxd, я попробовала
  • этим кодом сделать синий более насыщенным (saturated) только
  • там где лицо.
  • Надеюсь получилось более понятно объяснить ) Простите!
Ducol ()
Ответ на: комментарий от Ducol

у меня все сообщение теперь как список, но так вроде удобнее читать. и почему-то у меня отсутствует правка моих ответов на комментарии. но это сейчас не главное.

Ducol ()
Ответ на: комментарий от anonymous

Если Вы видите, что в коде что-то не так, пожалуйста, напишите конкретно. Этот код сделан, как я писала, преподавателями американского курса, который я пытаюсь пройти самостоятельно, и поскольку я совсем новичок, то мне интересно узнавать мнение профессионалов в отношении предложенных программ. Спасибо. Также я не сама выбираю формат, а следую курсу.

Ducol ()
Ответ на: комментарий от Ducol

Смотри.

Чтобы просто начать новый абзац (без списка), просто сделай два перевода строки подряд:

Абзац 1.
Всё ещё абзац 1, перенос строки исчезнет.

А вот теперь уже абзац 2.

А списки стоит применять только там, где действительно нужно что-то перечислить.

P. S.: вопросы по программированию/разработке нужно задавать в подфоруме Development, а не General. Это на будущее. Вероятно, кто-то из модераторов переместит этот тред туда.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 2)

Пожалуйста, помогите разобраться.

Я подумала, что можно вместо того, чтобы усилить синий на лице,

перевести все синие пиксели в черные, то есть сделать синий 0х00, зеленый и красный тоже 0х00 для тех пикселей, где виден голубой.

Но я не понимаю, в правильном ли я направлении действую?

Правильно ли основываться на информации полученной от xxd и

как ее правильно читать, чтобы изменить именно нужные цвета?

Спасибо!

Ducol ()
Ответ на: комментарий от Ducol

Подсказка для тех кто будет проходить cs50 и накопает это, код во втором if не сработает корректно, т.к. белый цвет (ffffff) также содержит red=ff.

anonymous ()

2) поменять цвет пикселей, в которых красный *не равен* 0xff

А что, по-вашему, должно будет получиться вместо бело-синих пикселей?

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.