Неправильный цвет при использовании CopyRect для копирования с большого изображения на меньший холст
Я писал функцию сжатия исходного изображения (файл JPG) в соответствии с изображением размером 170 x 200 пикселей. Исходное JPG-изображение было загружено в TImage (Image1, фиксированный размер 400 x 400px, растянуто для сохранения соотношения сторон), затем пользователь создаст прямоугольник выбора, чтобы установить область для копирования, а затем изображение будет скопировано используя CopyRect() на TImage назначения (Image2).
void __fastcall TSizePhotoForm::Button3Click(TObject *Sender)
{
float scale, base = 400.0f;
TRect crect; // copy rect
Image2->Width = 170;
Image2->Height = 200;
Image2->Canvas->CopyMode = cmSrcCopy;
TJPEGImage *img = new TJPEGImage();
img->LoadFromFile(fname);
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->Assign(img);
scale = (float)img->Width / base;
crect.Left = srect.Left * scale; // srect = source rect
crect.Top = srect.Top * scale;
crect.Right = crect.Left + (srect.Width() * scale);
crect.Bottom = crect.Top + (srect.Height() * scale);
Image2->Canvas->CopyRect(TRect(0, 0, w, h), bmp->Canvas, crect);
delete img;
delete bmp;
}
Проблема в том, что результирующий цвет изображения не правильный, и я заметил, что чем больше исходное изображение, тем резче смещение цвета результирующего изображения.
Любая идея, что не так и как мне избавиться от этой проблемы смещения цвета? Заранее спасибо.
1 ответ
Хорошо, я пытался воссоздать твою проблему Image2
формат пикселей это проблема. Я полагаю, вы получили pf8bit
установить и JPG pf24bit
так что он усекается до зеленоватого... Также копировать прямоугольник является изменчивым и StretchDraw
это намного плавнее. Вот сравнение:
И ваш обновленный код (при условии Image1
является исходным левым изображением и Image2
увеличенное изображение справа):
Как вы можете видеть StretchDraw
Лучше всего не знать, почему они не используют одни и те же методы масштабирования.
int h,w;
float scale, base = 400.0f;
TRect crect; // copy rect
TRect srect; // I assume some mouse selected rectangle I set it manualy instead
// init and load
Image2->Canvas->CopyMode = cmSrcCopy;
TJPEGImage *img = new TJPEGImage();
img->LoadFromFile("in.jpg");
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->Assign(img);
// I assume this is how you are rendering/store your left (source) image
Image1->Width = bmp->Width; // set dersired size
Image1->Height = bmp->Height;
Image1->Left = 10;
Image1->Top = 10;
Image1->Canvas->Draw(0,0,bmp);
// I assume this is your mouse selection
srect=TRect(90,34,192,154);
h=120; w=102;
// just render into Image1 for visual check
Image1->Canvas->Pen->Color=clYellow;
Image1->Canvas->Pen->Style=psDashDot;
Image1->Canvas->Brush->Style=bsClear;
Image1->Canvas->Rectangle(srect);
Image1->Canvas->Pen->Style=psSolid;
Image1->Canvas->Brush->Style=bsSolid;
// place and resize Image2 next to Image1
Image2->Top=10;
Image2->Left=Image1->Width+20;
Image2->Width = 170;
Image2->Height = 200;
// scaling
scale = (float)img->Width / base;
crect.Left = srect.Left * scale; // srect = source rect
crect.Top = srect.Top * scale;
crect.Right = crect.Left + (srect.Width() * scale);
crect.Bottom = crect.Top + (srect.Height() * scale);
// this is how you change the pixelformat
Image2->Picture->Bitmap->PixelFormat=pf32bit;
// your copy rect alternative
// Image2->Canvas->CopyRect(TRect(0,0,h,w), bmp->Canvas, crect);
// my stretch draw alternative
Graphics::TBitmap *tmp=new Graphics::TBitmap;
tmp->PixelFormat=pf32bit;
tmp->SetSize(srect.Width(),srect.Height());
tmp->Canvas->CopyRect(TRect(0,0,srect.Width(),srect.Height()), bmp->Canvas, srect);
Image2->Canvas->StretchDraw(TRect(0,0,srect.Width(),srect.Height()),tmp);
delete tmp;
// exit
delete img;
delete bmp;
Если вы хотите узнать больше о растровом пиксельном формате и быстром прямом пиксельном формате, смотрите:
Также имейте в виду, что Assign
а также LoadFrom...
звонки меняют формат пикселя...
Предварительное 8-битное изображение немного отличается от вашего, но у меня не было вашего входного изображения, вместо этого я использую скриншот, который вы разместили, в кодировке PNG, обрезанный и перекодированный в JPG, так что в расчете на пиксель существуют наиболее вероятные различия в цвете, и они могут быть даже в позиция +/-1px
Как вы заметили, чем больше площадь, тем больше искажений в цвете. Это связано с тем, что в 8-битных пиксельных форматах вы получаете только 256 цветов в палитре, и если ваше изображение содержит больше цветов, больше из них усекается. Чем больше выделенная область, тем больше пикселей и, следовательно, различных цветов присутствуют на изображении. GDI имеет немного плохое квантование цветов, что приводит к тому, что вы видите... Если вы хотите что-то лучше (если вы используете 8-битные изображения в качестве вывода), попробуйте следующее:
Также, как вы можете видеть CopyRect
не уместился в прямоугольник выбора, скорее всего, из-за усечения масштабирования (похоже, что они используют плохую целочисленную математику вместо подразделенного DDA или билинейной фильтрации, чтобы "оптимизировать" скорость)