• 0
sviat9440

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

Вопрос

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

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

Изменено пользователем sviat9440

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

22 ответа на этот вопрос

  • 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
Только что, dnekrasov сказал:

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

Спасибо, буду пробовать

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 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
wamaco, AlexG и Rusland понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 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

Что-ж, буду пробовать попиксельное сглаживание, других вариантов пока не вижу

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Выложите куда-нибудь картинку, которую вы ресайзите, а лучше проект

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 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 пользователей

    Нет пользователей, просматривающих эту страницу