• 0
AlexG

Как определить отсутствие изображения как такового в TBitmap?

Вопросы

Привет, друзья!

Подскажите - как, с максимально возможной скоростью, определить отсутствие изображения как такового в TBitmap?

Т.е. - есть TBitmap. Он либо заполнен изображением (картинка), либо он - абсолютно черный прямоугольник.

Каким способом можно узнать - что в нем именно изображение? Т.е. - НЕ абсолютно черный прямоугольник...

И определить это нужно "мгновенно" (условно выражаясь).

Заранее всем благодарен за участие!

P.S. Варианты типа того что ниже - не предлагать)) Хотелось бы что-то "побыстрее"! Еще раз спасибо!

function IsBitmapEmpty(Bmp: TBitmap): Boolean;
var
  X, Y   : Integer;
  BmpData: TBitmapData;
  yAddr  : Integer;
  AlphaCount : integer;
begin
  Result := False;
  try
    AlphaCount := 0;
    Bmp.Map(TMapAccess.Read, BmpData);
    for Y := 0 to Bmp.Height div 2 do
      begin
        YAddr := Y * Bmp.Height;
        for X := 0 to Bmp.Width - 1 do
          if (PAlphaColorArray(BmpData.Data)^[YAddr + X] <> TAlphaColorRec.Null) and
             (PAlphaColorArray(BmpData.Data)^[YAddr + X] <> TAlphaColorRec.Black) then
            begin
              inc(AlphaCount);
              Break;
            end;
        if AlphaCount > 0 then
          Break;
      end;
  finally
    Bmp.Unmap(BmpData);
    Result := AlphaCount = 0;
  end;
end;

 

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

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


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

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

  • 0

А зачем вам подряд все пиксели перебирать. Можно по диагонали перебрать к примеру 20-30 пикселей (5%-10% из всех пикселей из этой диагонали-линии).

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, ENRGY сказал:

А зачем вам подряд все пиксели перебирать. Можно по диагонали перебрать к примеру 20-30 пикселей (5%-10% из всех пикселей из этой диагонали-линии).

Я об этом думал. Однако, возможно есть другое решение? Более "правильное"...

Может можно как-то быстро обработать фрагмент памяти, в котором находится битмап, а не бегать циклом по пикселям, сравнивая цвета.

Потому и задал такой вопрос - возможно кто-то знает как это сделать.

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


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

Странная потребность, если не вариант пробежать по диагонали, тогда, возможно как вариант)):

создайте массив размера Width * Height * глубину (на 4 в случае  32 bit);

Глубина в данном случае не совсем корректно, чтоб было понятно: на R+G+B+Alpha

обнулите его через, увы не силен в Delphi на ++ через ZeroMemory;

Byte *destPtr;
destPtr = (Byte*)bitmap->ScanLine[bitmap->Height - 1]

это указатель на начало dib битмапа;

ну а дальше сравните просто сравните два участка памяти через memcmp или как угодно.

Не факт что сработает, но попробовать можно. Я таким макаром сравнивал изображения, когда нужно было очень быстро.

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

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


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

1) Какие размеры у битмапа?

2) Как и кто заполняет или не заполняет Bitmap

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
12 минут назад, Равиль Зарипов (ZuBy) сказал:

1) Какие размеры у битмапа?

2) Как и кто заполняет или не заполняет Bitmap

1. Размеры: 320*240, 640*480, 640*360 и др.

2. Заполняет битмапы декодер (в потоках формируется битмап, который копируется, в итоге, в конечный битмап, который и нужно проверить). НЕ заполняться он не может, в нем всегда есть изображение. Другой вопрос, что весь битмап может быть абсолютно "пустым"-черным.

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


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

У TBitmap есть такой метод, посмотрите его

function TBitmap.EqualsBitmap(const Bitmap: TBitmap): Boolean;
var
  MyMap, BitmapMap: TBitmapData;
  I: Integer;
begin
  if IsEmpty or Bitmap.IsEmpty then
  begin
    Result := IsEmpty and Bitmap.IsEmpty;
    Exit;
  end;
  Result := (Width = Bitmap.Width) and (Height = Bitmap.Height) and (PixelFormat = Bitmap.PixelFormat);
  if Result then
  begin
    if Map(TMapAccess.Read, MyMap) then
    try
      if Bitmap.Map(TMapAccess.Read, BitmapMap) then
      try
        for I := 0 to Height - 1 do
          if not CompareMem(MyMap.GetScanline(I), BitmapMap.GetScanline(I), MyMap.BytesPerLine) then
          begin
            Result := False;
            Exit;
          end;
      finally
        Bitmap.Unmap(BitmapMap);
      end;
    finally
      Unmap(MyMap);
    end;
  end;
end;

 

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
6 минут назад, Равиль Зарипов (ZuBy) сказал:

У TBitmap есть такой метод, посмотрите его


function TBitmap.EqualsBitmap(const Bitmap: TBitmap): Boolean;
var
  MyMap, BitmapMap: TBitmapData;
  I: Integer;
begin
  if IsEmpty or Bitmap.IsEmpty then
  begin
    Result := IsEmpty and Bitmap.IsEmpty;
    Exit;
  end;
  Result := (Width = Bitmap.Width) and (Height = Bitmap.Height) and (PixelFormat = Bitmap.PixelFormat);
  if Result then
  begin
    if Map(TMapAccess.Read, MyMap) then
    try
      if Bitmap.Map(TMapAccess.Read, BitmapMap) then
      try
        for I := 0 to Height - 1 do
          if not CompareMem(MyMap.GetScanline(I), BitmapMap.GetScanline(I), MyMap.BytesPerLine) then
          begin
            Result := False;
            Exit;
          end;
      finally
        Bitmap.Unmap(BitmapMap);
      end;
    finally
      Unmap(MyMap);
    end;
  end;
end;

 

Интересно!

Т.е., как я понимаю, идея такова - перед тем как начать сравнивать (искать "пустой" битмап), создаем прототип "пустого" битмапа (нужного размера, так как знаем - с чем надо будет сравнивать), а дальше уже каждое изображение сравниваем с данным прототипом?

Гуд. Попробую. Спасибо!

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


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

да, именно так! на счёт скорости конечно незнаю, не пробовал/не сравнивал.

потом отпишитесь, если все получится

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От Tot999
      Добрый день! 
      Решил покопаться в своей старой спрайтовой игрушке, чтобы освежить в памяти знания и состряпать что-нибудь новое. Возникли сомнения, нормально ли сделано графическое отображение, можно ли доработать.
      Все спрайты в дизайнтайме распиханы по Timagelist-ам.  На старте приложения я загружаю битмапы из имэджлистов в свои обджектлисты, подгоняя под нужный размер. 
      MeduzasBitmpAr : array [1..numofMeduzas] of TObjectList<Tbitmap>;  
      Дальше рисую по таймеру в основном окне игры Tpaintbox.OnPaint:
               
      В принципе, даже на слабеньких телефончиках, всё вроде бодро. Но может, опытные товарищи чего подскажут, а то я 3ий день в собственном соку варюсь, ничего толкового.
    • От SIARHEI RAHOUSKI
      Создал проект там куча компонентов. Но разворачивании формы на весь экран компоненты размер не меняют:
      Прочитал про свойства align Но как только я выставлю Group box например left другим right все сбивается в кучу и поправить это не могу. 
      Как настроить align ?

    • От SIARHEI RAHOUSKI
      Как сделать форму с компонентами под все разрешения?

    • От SIARHEI RAHOUSKI
      Как сделать мозаику (drag/drop) ? Получается есть 2 прямоугольника (которые надо перетаскивать)  и есть ещё 2 прямоугольника (которые должны принимать) и ещё есть кнопка проверки. При нажатии определяет правильно ли разместили прямоугольники.
    • От Антон Емельянов
      Приложение не даёт DeviceToken...  ,  (DeviceID есть)
      FDeviceToken := FPushService.DeviceTokenValue[TPushService.TDeviceTokenNames.DeviceToken];

      Тест пример реализован по статье нашего замечательного модератора
      http://blog.rzaripov.kz/2017/02/firebase-android-ios-2.html

      Используется:
      Компиляция SDK Android 5.1
      Среда-разработки Delphi XE 10.2 

      Пожалуйста запустите проект на своей версии Delphi..
      Посмотрите будет  сгенерирован ТОКЕН или нет.. 
      в случае удачи ,  напишите какая у вас версия Дельфи..

      Исходник-проекта:  https://drive.google.com/open?id=1mCPvYYd0tXBALt-J_ymVuzChj_TtztC0
      Только APK: https://drive.google.com/open?id=1x8q4RyVylpGOMjcQYjlvFxFBSQaYs7NL 


      Помогите люди добрые 
      За помощь и консультацию отблагодарю..
       

    • От AliZairov
      Привет. Я сделал новую версию YouTubeApi компоненты. Поддерживаемые VCL & FMX + Mobile.
      Никаких официальных YouTube Api компоненты. Только данные с парсинг. Пример доступен в архиве.
       
      Новый
      ===
      v1.4 - 25/02/2018
        + Устранение проблем
      YouTubeApiDelphi
    • От gresaggr
      Добрый день.
      Как под FMX в ListView сделать подчеркивание Detail в рантайме?
      Пытался делать так:
      LV.ItemAppearanceObjects.ItemObjects.Detail.Font.Style := [TFontStyle.fsUnderline]
      но не срабатывает.
      P.S. Возможно это применить не ко всем строкам, а только к некоторым?
    • От Виталий Иванов
      Ошибка при запуске программы на отладку:
       
      "
      Can't open socket: Permission denied 
      Exiting
      .
      "
       
      кто знает как побороть ? 
       
      Отладку запускаю на OnePlus3 с Android 8.0.0, драйвера Google USB переустанавливал. 

    • От x11
      Можно ли получить TBitmap из TBitmapImage? Конвертировать.
    • От dim
      Есть код который работает при смещении карты и получив координаты центра пытаюсь получить адрес по ним.
      procedure TMasterDetailForm.MapView3CameraChanged(Sender: TObject); var myCoordinat: TLocationCoord2D; begin inherited; myCoordinat.Create(MapView3.Location.Latitude,MapView3.Location.longitude); if (int(myCoordinat.Latitude)<>0) then begin //проверяю, что координаты определены if not Assigned(fGeocoder) then begin if Assigned(fGeocoder.Current) then fGeocoder := TGeocoder.Current.Create; if Assigned(fGeocoder) then fGeocoder.OnGeocodeReverse := OnGeocodeReverseEventStart; end; if Assigned(fGeocoder) and not fGeocoder.Geocoding then fGeocoder.GeocodeReverse(myCoordinat); end end; все работало до очередного обновления, а сейчас ругается "java.io.IOException: Service not Available" на fGeocoder.GeocodeReverse(myCoordinat);
      подскажите куда копать
  • Последние посетители   0 пользователей онлайн

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