• 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

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

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

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


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

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

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

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

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

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

Войти

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

Войти


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

    • От Антон Емельянов
      Приложение не даёт 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);
      подскажите куда копать
    • От striker
      Всем привет!
      Нужен совет.
      Есть Grid, в нем расписание дня.
      В БД каждая строка это отдельная запись.
      Нужно как-то визуально сделать подобие объединения ячеек в Excel.
      Т.е. нужно занять расписание на 2 часа.
      При этом функционал по событиям для строки "второго часа" должен быть недоступен.
      Может хотя бы границу стирать, т.е. оставлять значение в верхней ячейки, а нижнюю просто не отображать.
      Как это лучше сделать?
      FMX, Windows, Delphi XE6, MySQL
       

    • От x11
      Нет ли у FMX готовой функции для открытия веб-ссылок из приложения?
      А то приходится городить огород с лисапетами и кучей IFDEF.
      В итоге что у меня получилось.
      Для удобства разнес все по разным модулям.
      Модуль для Windiws
      unit uUtilsWindows; interface {$IFDEF MSWINDOWS} uses ShellApi, Variants, Windows, FMX.Types, FMX.Platform.Win; procedure WindowsOpenUrl(const sUrl: string; WindowHandle: TWindowHandle); {$ENDIF} implementation {$IFDEF MSWINDOWS} procedure WindowsOpenUrl(const sUrl: string; WindowHandle: TWindowHandle); begin ShellExecute(FmxHandleToHWND(WindowHandle), 'open', PChar(VarToStr(sURL)), nil, nil, SW_NORMAL); end; {$ENDIF} end.  
      Модуль для Android
      unit uUtilsAndroid; interface {$IFDEF ANDROID} uses FMX.Helpers.Android, Androidapi.JNI.Net, Androidapi.JNI.GraphicsContentViewText, AndroidApi.Helpers; procedure AndroidOpenUrl(const sUrl: string); {$ENDIF} implementation {$IFDEF ANDROID} procedure AndroidOpenUrl(const sUrl: string); Var Uri: Jnet_Uri; OpenLinkIntent: JIntent; begin Uri := StrToJURI(sUrl); OpenLinkIntent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW, Uri);// будем что-то смотреть OpenLinkIntent.addCategory(TJIntent.JavaClass.CATEGORY_BROWSABLE);// смотреть в браузере OpenLinkIntent.setData(Uri);// смотреть эту ссылку SharedActivity.startActivity(OpenLinkIntent);// открываем end; {$ENDIF} end.  
      теперь в основной форме:
      uses ..., ...{$IFDEF ANDROID}, vkbdhelper, uUtilsAndroid{$ENDIF} {$IFDEF MSWINDOWS}, uUtilsWindows {$ENDIF}; ... ... ... procedure TfmEditObject.actOpenUrlExecute(Sender: TObject); begin {$IFDEF ANDROID}AndroidOpenUrl(edMapsCoordUrl.Text);{$ENDIF} {$IFDEF MSWINDOWS}WindowsOpenUrl(edMapsCoordUrl.Text, Self.Handle);{$ENDIF} end;  
      А если добавлять ещё одну платформу, то ещё один модуль понадобится.
      Может есть более правильный вариант, так сказать, дизайна исходного кода?
       
    • От SerhioUser
      Добрый день.
      Как в FMX при перерисовке объекта включить/отключить привязку к вертикальной синхронизации (v-sync) развертки экрана? Есть ли такая возможность в FMX? (В OpenGL и DirectX - есть)
      Например если делаем видео-плеер, то чтобы не было артефактов синхронизация нужна, а если хотим узнать реальный fps - синхронизацию выключаем.
    • От Freezer_86
      Пишу кроссплатформенное приложение. Результат поиска отображается в TGrid. Стал вопрос отображения картинки в одной из колонок.
      На Windows все ок, но на планшете происходят просто чудеса: при первом отображение все корректно, но если простоколить вверх-вниз как картинки одни перетираются другими, часть вообще отображается вверх ногами.
      Код для сохранение картинки(jpg) в базу:
      if Assigned(sm) then begin sm.Position := 0; //TBlobField(dmData.cdsPlayerData.FieldByName('Photo')).LoadFromStream(sm); vImage := TImage.Create(nil); try sm.Position := 0; vImage.Bitmap.LoadFromStream(sm); vKoef := vImage.Bitmap.Height / 64; vImage.Bitmap.Resize(Trunc(vImage.Bitmap.Width / vKoef), Trunc(vImage.Bitmap.Height / vKoef)); sm.Free; sm := TMemoryStream.Create(); try vImage.Bitmap.SaveToStream(sm); TBlobField(dmData.cdsPlayerData.FieldByName('SmallPhoto')).LoadFromStream(sm); finally sm.Free; end; finally vImage.Free; end; end{if}; До скрола:

      После скрола:

      Пробовал и LiveBinding, и ручную прорисовку - результат один и тот же. Есть идеи что не так?
      P.S. Знаю что нужно делать через TListView, но заказчик хочет «сеточку как в старой программе», так как на android будет работать только на планшетах – я согласился.
       
  • Последние посетители   0 пользователей онлайн

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