Перейти к содержанию
Fire Monkey от А до Я
  • 0

TBitmap сглаживание


sviat9440

Вопрос

Всем привет. Столкнулся вот с такой проблемой: если залить битмап большого размера в маленький, то получается битмап с артефактами. Я умный, сделал Bitmap.CreateThumbnail(180, 180) (180 - высота и ширина TImage). Артефактов стало гораздо меньше, но изображение все равно выглядит ступеньками. И тут я понял, что не знаю как сглаживать битмап. Так вот собственно вопрос: как сглаживать битмап?

P.S. На одном умном форуме предлагали юзать блюр. Я не придумал шутку, это и так смешно))

Изменено пользователем sviat9440
Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Скорее никак, сглаживаются примитивы при прорисовке по канве компонента на форме.

Вот тут обсуждали http://fire-monkey.ru/topic/1927-сглаживание-при-рисовании-в-буфер-bitmap/

 

Ссылка на комментарий
  • 0

Ясно, да читал, но к сожалению методы описанные там не принесли результата.

Я вот столкнулся с таким примером сглаживания (не знаю как он работает на практике) он для VCL.

Спойлер

var x, y: integer;
   r, b, g: byte;
begin
   with Image3.picture.Bitmap.canvas do
   begin
     for x:=1 to Image3.picture.Bitmap.Width-1 do
       for Y:=1 to Image3.picture.Bitmap.height-1 do
       begin
         r:=(GetRValue(Pixels[x-1,y-1])+
           GetRValue(Pixels[x,y-1])+
           GetRValue(Pixels[x+1,y-1])+
           GetRValue(Pixels[x-1,y])+
           GetRValue(Pixels[x+1,y])+
           GetRValue(Pixels[x-1,y+1])+
           GetRValue(Pixels[x,y+1])+
           GetRValue(Pixels[x+1,y+1])+
           GetRValue(Pixels[x,y])) div 9;
         g:=(GetGValue(Pixels[x-1,y-1])+
           GetGValue(Pixels[x,y-1])+
           GetGValue(Pixels[x+1,y-1])+
           GetGValue(Pixels[x-1,y])+
           GetGValue(Pixels[x+1,y])+
           GetGValue(Pixels[x-1,y+1])+
           GetGValue(Pixels[x,y+1])+
           GetGValue(Pixels[x+1,y+1])+
           GetGValue(Pixels[x,y])) div 9;
         b:=(GetBValue(Pixels[x-1,y-1])+
           GetBValue(Pixels[x,y-1])+
           GetBValue(Pixels[x+1,y-1])+
           GetBValue(Pixels[x-1,y])+
           GetBValue(Pixels[x+1,y])+
           GetBValue(Pixels[x-1,y+1])+
           GetBValue(Pixels[x,y+1])+
           GetBValue(Pixels[x+1,y+1])+
           GetBValue(Pixels[x,y])) div 9;
         Pixels[x,y]:=RGB(r,g,b);
       end;
   end;
end;

 

Я его пытался реализовать на FMX. Ну как пытался. Завис в самом начале. Я не знаю как в FMX получить цвет определенного пикселя на канве. А уж тем более не знаю как задать пикселю на канве определенный цвет. ))))

Ссылка на комментарий
  • 0
7 минут назад, sviat9440 сказал:

Я не знаю как в FMX получить цвет определенного пикселя на канве. А уж тем более не знаю как задать пикселю на канве определенный цвет

Цвет пикселя битмапки получить очень просто:

var
  bmd: TBitmapData;
  bmp: TBitmap;
begin
  ...
  if bmp.Map(TMapAccess.ReadWrite, bmd) then
  try
    // здесь работаем с TBitmapData - у него есть все что нужно, чтобы работать с пикселями
  finally
    bmp.Unmap(bmd);
  end;
end;

 

Ссылка на комментарий
  • 0
13 часов назад, sviat9440 сказал:

Так вот собственно вопрос: как сглаживать битмап?

Canvas.DrawBitmap - последний параметр этого метода отвечает за сглаживание.
 

Ссылка на комментарий
  • 0
1 минуту назад, dnekrasov сказал:

Canvas.DrawBitmap - последний параметр этого метода отвечает за сглаживание.

Эм. Буду разбираться как его применить, спасибо...

Ссылка на комментарий
  • 0

знакомо... это работало крайне медленно, перебор по пикселям, немного быстрее там было считывать line,

тот же эффект в FMX даст Canvas->Blending = true

Изменено пользователем Камышев Александр
Ссылка на комментарий
  • 0

как вариант - мультисемлинг:

Создать битмап в 4 раза больше чем надо, задать у канвы матрицу все увеличивающую в 4 раза.

А после отрисовки, рисовать со сглаживанием наш битмап в другой, в 4 раза меньший. Это даст не мега качественное, но сглаживание.

Ссылка на комментарий
  • 0
11 минут назад, sviat9440 сказал:

Эм. Буду разбираться как его применить, спасибо...

Все просто:

bmpDest.Canvas.BeginScene;
try
  bmpDest.Canvas.DrawBitmap(bmpSource, RectF(0, 0, bmpSource.Width, bmpSource.Height), RectF(0, 0, bmpDest.Width, bmpDest.Height), 1, False);
finally
  bmpDest.Canvas.EndScene;
end;

и в bmpDest вы получите Вашу битмапку сглаженную и с новыми размерами

Изменено пользователем dnekrasov
Ссылка на комментарий
  • 0
8 часов назад, dnekrasov сказал:

в bmpDest вы получите Вашу битмапку сглаженную и с новыми размерами

Вот код:

Спойлер

bmpSource := TBitmap.Create;
bmpDest := TBitmap.Create;
bmpSource := QPicture;
bmpDest.SetSize(180, 180);
bmpDest.Canvas.BeginScene;
try
  bmpDest.Canvas.DrawBitmap(bmpSource, RectF(0, 0, bmpSource.Width,
  bmpSource.Height), RectF(0, 0, bmpDest.Width, bmpDest.Height),
  1, False);
finally
  bmpDest.Canvas.EndScene;
end;
QImage.Bitmap := bmpDest;
bmpSource.Free;
bmpDest.Free;

Но все равно, картинка в QImage.Bitmap "ступеньками".

Ссылка на комментарий
  • 0
8 часов назад, Error сказал:

как вариант - создать битмап в 4 раза больше чем надо, задать у канвы матрицу все увеличивающую в 4 раза.

Не вариант. Я точно не буду знать какая у меня пикча, какую юзер загрузит, ту и должно обработать (не меньше 180 пикселей естественно).

Ссылка на комментарий
  • 0

Хорошо. Вот исходная пикча:

Спойлер

logo.PNG

Вот результат сжатия до 180х180.

Спойлер

2016-11-16_18-36-42.png

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

P.S. Ах да, можно же кодом размер миниатюры высчитывать, чтобы уменьшать пропорционально.

Изменено пользователем sviat9440
Ссылка на комментарий
  • 0
10 часов назад, Камышев Александр сказал:

знакомо... это работало крайне медленно, перебор по пикселям, немного быстрее там было считывать line,

тот же эффект в FMX даст Canvas->Bending = true

мб: Blending?

Ссылка на комментарий
  • 0
10 часов назад, Камышев Александр сказал:

угу

Только вот либо я не правильно установил True, либо оно не работает.

Спойлер

var
  QImage: TImage;
  PLoad: TBitmap;
//...
  QImage.Bitmap.Canvas.Blending := True;
  QImage.Bitmap := PLoad;

 

 

Ссылка на комментарий
  • 0

Здесь проблема не в размытии а в используемом алгоритме ресамплинга. Delphi, похоже, использует "по соседним пикселям". Вам же надо - бикубический.

Единственное что можно посоветовать - найдите какой-нибудь пакет компонент для работы с графикой или сами реализуйте этот алгоритм.

Ссылка на комментарий
  • 0
void __fastcall TForm1::FormPaint(TObject *Sender, TCanvas *Canvas, const TRectF &ARect)
{
Canvas->BeginScene();
TRect rect = Rect( 10, 10, 100, 100 );
TRect src = Rect( 0, 0, ImageControl1->Bitmap->Width, ImageControl1->Bitmap->Height );
Canvas->DrawBitmap( ImageControl1->Bitmap, src, rect, 1, false );
Canvas->EndScene();
}

Где проблема то?

2016-11-18_10-04-37.png

Ссылка на комментарий
  • 0
В 18.11.2016 в 10:07, Камышев Александр сказал:

Где проблема то?

Спойлер

procedure TForm2.Image1Click(Sender: TObject);
begin
  Canvas.BeginScene;
  Canvas.DrawBitmap(Image1.Bitmap, RectF(0, 0, Image1.Bitmap.Width, Image1.Bitmap.Height), RectF(0, 0, 100, 100), 1, False);
  Canvas.EndScene;
end;

photo_2016-11-19_11-10-28.jpg

Да как то не вижу особо никаких отличий... Как было с артефактами так и осталось

Ссылка на комментарий
  • 0

Короче, весь вот этот код:

Спойлер

procedure TBitmapH.Smoothing;
var
  x, y: Integer;
  bmd: TBitmapData;
  rec: TAlphaColorRec;
begin
  bmd := TBitmapData.Create(self.Width, self.Height, TPixelFormat.RGBA32F);
  if self.Map(TMapAccess.ReadWrite, bmd) then
    try
      for x := 0 to bmd.Width - 1 do
        for y := 0 to bmd.Width - 1 do
        Begin
          rec.r := (TAlphaColorRec(bmd.GetPixel(x, y)).r +
            TAlphaColorRec(bmd.GetPixel(x - 1, y)).r +
            TAlphaColorRec(bmd.GetPixel(x, y - 1)).r +
            TAlphaColorRec(bmd.GetPixel(x - 1, y - 1)).r +
            TAlphaColorRec(bmd.GetPixel(x + 1, y - 1)).r +
            TAlphaColorRec(bmd.GetPixel(x + 1, y)).r +
            TAlphaColorRec(bmd.GetPixel(x - 1, y + 1)).r +
            TAlphaColorRec(bmd.GetPixel(x, y + 1)).r +
            TAlphaColorRec(bmd.GetPixel(x + 1, y + 1)).r) div 9;
          rec.g := (TAlphaColorRec(bmd.GetPixel(x, y)).g +
            TAlphaColorRec(bmd.GetPixel(x - 1, y)).g +
            TAlphaColorRec(bmd.GetPixel(x, y - 1)).g +
            TAlphaColorRec(bmd.GetPixel(x - 1, y - 1)).g +
            TAlphaColorRec(bmd.GetPixel(x + 1, y - 1)).g +
            TAlphaColorRec(bmd.GetPixel(x + 1, y)).g +
            TAlphaColorRec(bmd.GetPixel(x - 1, y + 1)).g +
            TAlphaColorRec(bmd.GetPixel(x, y + 1)).g +
            TAlphaColorRec(bmd.GetPixel(x + 1, y + 1)).g) div 9;;
          rec.b := (TAlphaColorRec(bmd.GetPixel(x, y)).b +
            TAlphaColorRec(bmd.GetPixel(x - 1, y)).b +
            TAlphaColorRec(bmd.GetPixel(x, y - 1)).b +
            TAlphaColorRec(bmd.GetPixel(x - 1, y - 1)).b +
            TAlphaColorRec(bmd.GetPixel(x + 1, y - 1)).b +
            TAlphaColorRec(bmd.GetPixel(x + 1, y)).b +
            TAlphaColorRec(bmd.GetPixel(x - 1, y + 1)).b +
            TAlphaColorRec(bmd.GetPixel(x, y + 1)).b +
            TAlphaColorRec(bmd.GetPixel(x + 1, y + 1)).b) div 9;;
          rec.A := (TAlphaColorRec(bmd.GetPixel(x, y)).A +
            TAlphaColorRec(bmd.GetPixel(x - 1, y)).A +
            TAlphaColorRec(bmd.GetPixel(x, y - 1)).A +
            TAlphaColorRec(bmd.GetPixel(x - 1, y - 1)).A +
            TAlphaColorRec(bmd.GetPixel(x + 1, y - 1)).A +
            TAlphaColorRec(bmd.GetPixel(x + 1, y)).A +
            TAlphaColorRec(bmd.GetPixel(x - 1, y + 1)).A +
            TAlphaColorRec(bmd.GetPixel(x, y + 1)).A +
            TAlphaColorRec(bmd.GetPixel(x + 1, y + 1)).A) div 9;
          bmd.SetPixel(x, y, rec.Color);
        End;
    finally
      self.Unmap(bmd);
    end;
end;

 

Дает вот такой результат:

Спойлер

photo_2016-11-19_20-59-35.jpg

мдаа

Ссылка на комментарий
  • 0

http://stackoverflow.com/questions/1976116/scale-an-image-nicely-in-delphi/1976171#1976171

https://github.com/norgepaul/TChromeTabs/tree/master/GDIPlus

Вот тут нашел реализацию GDI+. Только не могу разобраться как ее применить...

Изменено пользователем sviat9440
Ссылка на комментарий
  • 0

GDI+ можно применить только на Windows, насколько я разбираюсь. В связи с этим еще один вопрос, есть ли графическая библиотека для FMX, способная менять размер изображения с качеством, соответствующим следующим установкам GDI:

  graphicsGDIPlus.SetInterpolationMode(InterpolationModeHighQualityBicubic); 
  graphicsGDIPlus.SetSmoothingMode(SmoothingModeAntiAlias);

 

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...