Как правильно переконвертировать изображение в 1-битовое?

Хочу из 24 bit конвертнуть в 1-bit, т.е чтобы было всего 2 цвета - белый и черный.
Т.е сначала нужно создать палитру из 2 цветов - черного и белого, а потом для каждого пикселя определить - к какому из этих двух цветов он относится.

Палитру и перевод пикселей я сделал - я даже двумя способами попробовал -
через grayscale и через среднюю яркость пикселя, но для 1 битовых изображений это вроде как неважно.

Проблема то не в этом - а в том, как мне после всех этих хитрых манипуляций записать изображение.
Т.е если я все верно понял - в таком черно-белом изображении хранятся только индексы палитры - т.е в моем случае 1 или 0 .
Но после трех значений R G B следует еще и значение для прозрачности, где обычно хранится 0.
т.е если моя палитра -
00 00 00 00 FF FF FF 00
и первый пиксель белый - то его индекс 1 , а если черный - то 0

т.е как я думал это должно выглядеть -
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);


Но это выдает нечто такое -

0d92e07c10e54649aaa768d5ada106a0.jpg
Оригинал -
756447d4435f414383a5e2e2e8bb01bf.bmp
Что я делаю не так?

UPD
Изменил на >=8 , теперь уже ближе к истине , но все равно эти лесенки мне не нравятся..
adf55f55ba7e4087bf03909f5d748a9f.png

Вот код загрузки изображения -
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;
}


А как мне узнать, что строка не кратна 4 байтам ? Я же вроде побитово записываю...

UPD 2

Вот это работает ! =)
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
  • Вопрос задан
  • 1218 просмотров
Решения вопроса 1
alsopub
@alsopub
Для начала currbit>=7 надо заменить на currbit>=8, но проблема кажется не в этом.
Сходу сложно сказать в чем проблема, так как тут задействована еще и процедура чтения файла и сам исходный файл.
Есть еще момент - строка должна быть кратна 4 байтам.
Плюс биты заполняются не слева-направо, а справа-налево, то есть currbit должен пробегать значения не 0..7, а 7..0.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
abyrkov
@abyrkov
JavaScripter
Эм...
if (Rgbtriple[i][j].Blue>100)
Я так понял, вы только синий поверяете. А синего у вас почти нет...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы