E
E
Evgeny Trofimov2016-05-28 22:48:50
Programming
Evgeny Trofimov, 2016-05-28 22:48:50

How to properly convert an image to 1-bit?

I want to convert from 24 bit to 1-bit, i.e. to have only 2 colors - white and black.
That is, first you need to create a palette of 2 colors - black and white, and then for each pixel determine which of these two colors it belongs to.
I did the palette and pixel translation - I even tried it in two ways -
through grayscale and through the average brightness of a pixel, but for 1 bit images it doesn't seem to matter.
The problem is not in this - but in how I can record the image after all these tricky manipulations.
That is, if I understood everything correctly, only palette indexes are stored in such a black and white image - that is, in my case 1 or 0 .
But after three RGB values, there is also a value for transparency, where 0 is usually stored.
i.e. if my palette is
00 00 00 00 FF FF FF 00
and the first pixel is white - then its index is 1, and if black - then 0,
i.e. how I thought it should look -

for (int i=0;i<BMInfoHeader.Height;i++)
  for (int j=0;j<BMInfoHeader.Width;j++)
  {
    if (currbit>=7)//собрали байт
    {
      fwrite(&one_byte,1,1,f);//записали его
      one_byte=0;//обнулили его
      currbit=0;//обнулили счетчик для сдвига
    }
    if (Rgbtriple[i][j].Blue>100) //если больше опред. значения
    {
        one_byte|=(1<<currbit);//записываем 1
        currbit++;
    }
    else currbit++;//иначе - 0 (т.е просто сдвигаем вправо)
  }
  fwrite(&one_byte,1,1,f);//дописываю последний байт
  fclose(f);

But it gives something like -
0d92e07c10e54649aaa768d5ada106a0.jpg
Original -
756447d4435f414383a5e2e2e8bb01bf.bmp
What am I doing wrong?
UPD
Changed to >=8 , now it's closer to the truth, but I still don't like these ladders ..
adf55f55ba7e4087bf03909f5d748a9f.png
Here is the image loading code -
int Image::loadimage(char *filename)
{
    FILE *f; 
    int imageIdx=0;  //image index counter
 
  fopen_s(&f,filename,"rb");//открываем файл
    if (f == NULL) return 0;//если не смогли открыть - вызвращаем код ошибки - 0

    fread(&BMFileHeader, sizeof(BMFileHeader),1,f);//считали заголовок

  if (BMFileHeader.Type !=0x4D42)//проверили - точно ли формат .bmp
    {
        fclose(f);
        return 0;
    }
    
    fread(&BMInfoHeader, sizeof(BMInfoHeader),1,f); //считали информацию об изображении	
  //this->info();//вывели информацию

  if (BMInfoHeader.BitCount == 1 || BMInfoHeader.BitCount==4 || BMInfoHeader.BitCount==8)//проверка на палитровое изображение
  {
    loadpaletteimg(f);
    return 0;
  }
  
  fseek(f, BMFileHeader.OffsetBits, SEEK_SET); //переместили указатель в нужное место

  if (BMInfoHeader.BitCount==24)
  {
    Rgbtriple=new RGBTRIPLE*[BMInfoHeader.Height];
    Rgbquad=0;

    for (int i = 0; i < BMInfoHeader.Height; i++)//построчно
    {
      Rgbtriple[i]=new RGBTRIPLE[BMInfoHeader.Width];
      fread(Rgbtriple[i], sizeof(RGBTRIPLE), BMInfoHeader.Width, f);
    }
    if(Rgbtriple) cout<<"Изображение успешно загружено!"<<endl;
  }

  if (BMInfoHeader.BitCount==16)
  {
    Rgbquad=new RGBQUAD*[BMInfoHeader.Height];
    Rgbtriple=0;

    for (int i = 0; i < BMInfoHeader.Height; i++)//построчно
    {
      Rgbquad[i]=new RGBQUAD[BMInfoHeader.Width];
      fread(Rgbquad[i], sizeof(RGBQUAD), BMInfoHeader.Width, f);
    }
    if(Rgbquad) cout<<"Изображение успешно загружено!"<<endl;
  }
  else return 0;	
    fclose(f);
  return 1;
}

How do I know if a string is not a multiple of 4 bytes? I kind of write down bit by bit ...
UPD 2
This works! =)
byte one_byte=0;
  int currbit=0;
  byte mask=0X80;
  for (int i=0;i<BMInfoHeader.Height;i++)
  for (int j=0;j<BMInfoHeader.Width;j++)
  {
    if (currbit>=8)//собрали байт
    {
      fwrite(&one_byte,1,1,f);//записали его
      one_byte=0;
      currbit=0;
    }
    if (Rgbtriple[i][j].Blue>100) 
    {
        one_byte|=(mask>>currbit);
        currbit++;
    }
    else currbit++;
  }
  fwrite(&one_byte,1,1,f);//дописываю последний байт
  fclose(f);
}

6afd42702de040e2a221ecd8ed9609d7.gif

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexey, 2016-05-28
@deadrime

First, currbit>=7 should be replaced with currbit>=8, but that doesn't seem to be the problem.
It's hard to tell right away what the problem is, since both the file reading procedure and the source file itself are also involved here.
There is another point - the string must be a multiple of 4 bytes.
Plus, the bits are filled not from left to right, but from right to left, that is, currbit should run values ​​not 0..7, but 7..0.

D
Dark Hole, 2016-05-28
@abyrkov

Um ...
As I understand it, you only believe blue. And you don't have much blue...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question