PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Как сравнить две картинки с максимальной скоростью?


Как сравнить две картинки с максимальной скоростью?

Сообщений 1 страница 6 из 6

1

Здравствуйте!
Есть две картинки.
Допустим:
LoadImage(0, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee1.bmp")
LoadImage(1, #PB_Compiler_Home + "Examples\Sources\Data\GeeBee2.bmp")
Их необходимо сравнить поточечно и если хоть одна точка отличается, картинки разные.
Казалось бы элементарная задача, но....
К сожалению, функция Point не содержит такого параметра как номер изображения с которого считывается точка. Получается, что чтобы сравнить две картинки, одну из них надо загрузить в массив, а затем цвета точек второй картинки сравнивать со значениями в этом массиве...
   
Примерно так:

Код:
Height =ImageHeight(Num_Image)-1
Width = ImageWidth(Num_Image)-1
Dim Image_Array(Width, Height)
StartDrawing (ImageID(0))
For y=0 To Height
  For x=0 To Width
    Image_Array(x,y) = Point(x,y)
  Next x
Next y
StopDrawing()
StartDrawing (ImageID(1))
For y=0 To Height
  For x=0 To Width
    If Image_Array(x,y) <> Point(x,y)
      stop_image=1
      Break 2
    EndIf
  Next x
Next y
StopDrawing()

Всё бы ничего, но вот если мы сравниваем ни одну пару картинок, а множество пар картинок(в цикле), при этом картинки ещё и большие (например, размером с экран), то время 2 пары немаленьких циклов  дают о себе знать.
Можно, конечно сократить количество циклов до двух:

Код:
For y=0 To Height
  For x=0 To Width
    StartDrawing (ImageID(0))
    Image_Array(x,y) = Point(x,y)
    StopDrawing()
    StartDrawing (ImageID(1))
    If Image_Array(x,y) <> Point(x,y)
      stop_image=1
      Break 2
    EndIf
    StopDrawing()
  Next x
Next y

Но тогда код сильно замедляют StartDrawing\StopDrawing() А ведь это сравнение всего лишь двух картинок.
Допустим, нам надо сделать детектор изменения экрана....
Требуется:
1 сделать 2 скриншота
2 сравнить их между собой
3. если результат сравнения соответствует ожидаемому (например изображение поменялось\или не поменялось) - сообщить, в противном случае повторить цикл начиная с пункта 1.
Сам по себе скриншот делается почти мгновенно, а вот дальше начинаются проблемы, описанные выше. Даже запись цветов точек в массив по сравнению с временем создания скриншота, процесс долгий. Чтобы убедиться в этом достаточно сделать скриншот, а потом считать его по точкам. считывание займет куда больше времени чем сам скриншот!
И так при любой работе с графикой.... Например, если нам захочется, вдруг, (ради эксперимента) нарисовать картинку на весь экран по точкам(прорисовывая каждую точку отдельно, ну например из заранее заготовленного массива), мы буквально увидим, как по точкам появляется эта картинка) Однако если мы смотрим фильм с плейером на весь экран, кадры по точечкам у нас не прорисовываются(по крайней мере это происходит настолько быстро, что мы этого не замечаем). Это я к тому, что машина умеет быстро работать с графикой, причем как считывать её(время того же скриншота - почти мгновенно), так и выводить (видео, игры и т.п.) Вопрос лишь в том, "как это делается?"
Например:
1. Можно ли(и как) получить цвет точки картинки по координатам и номеру картинки не используя Point(x,y) и что более важно StartDrawing  \ StopDrawing()
2. Минуя StartDrawing сразу загрузить картинку в двухмерный массив?

0

2

Можно сравнить просто память CompareMemory()
С помощью EncodeImage() получаешь указатель на буфер данных или используешь тот что у тебя есть. То есть в идеале нужно создать не скриншот, или скриншот, но как данные в памяти и просто сравнивать его с новыми поступлениями. Ну или загружать рисунок кодировать его в BMP получая указатель и сравнивать две его версии.
На счёт видео и прорисовки по пикселям, разница, что видеоплеер формирует кадр в памяти, а потом рисует его один раз, а попиксельная прорисовка явно говорит о том что кадр недорисован и его пытаются вывести на экран монитора 1900*1080 = 2 миллиона раз, то есть 1 раз против 2 миллиона раз.

Отредактировано AZJIO (03.05.2023 08:10:59)

0

3

Nigri_lupus написал(а):

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

Как обычно трудно советовать, потому что нет ответа на главный вопрос: "с какой целью?"
Подозреваю что можно просто рассмотреть файлы как бинарные забыв про то, что там внутри изображение. И всё действительно становится элементарно.
https://www.purebasic.com/documentation … ddata.html
https://www.purebasic.com/documentation … emory.html

p.s. кстати https://www.purebasic.fr/english/viewto … 30#p600330
Fred: "Я проверил текущий код CompareMemory(), и мы не использовали memcmp(), который в два раза быстрее нашего пользовательского кода. Я изменил его для следующей бета-версии."

Отредактировано useful (03.05.2023 12:47:38)

0

4

AZJIO написал(а):

То есть в идеале нужно создать не скриншот, или скриншот, но как данные в памяти

Как это сделать? Можно коротенький кусочек кода?
Как сделать скриншот в виде Image - знаю:

Код:
 CreateImage(1, WindowWidth(2), WindowHeight(2))
hwnd = OpenWindow(2, 0, 0, 300, 300, "ScreenShotWindow", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #WS_EX_LAYERED)
 HDC = GetDC_(hwnd)
          DC = StartDrawing(ImageOutput(1))
          BitBlt_(DC, 0, 0, WindowWidth(2), WindowHeight(2) , GetDC_(GetDesktopWindow_()), WindowX(2) + 3, WindowY(2) + 31, #SRCCOPY)
StopDrawing()
ReleaseDC_(0, HDC)

     
Примерно так....   
А как сделать скриншот сразу в память?

0

5

useful написал(а):

Как обычно трудно советовать, потому что нет ответа на главный вопрос: "с какой целью?"

Почему же нет ответа - он есть.

Nigri_lupus написал(а):

Допустим, нам надо сделать детектор изменения экрана....

Тое сть отследить когда на экране(или на определенной части экрана) что-то изменилось(начало\прекратило меняться)
Своего рода аналог событий типа move, change только графические.... относительно того, что происходит на экране...

useful написал(а):

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

Ну, они тут не совсем в файлах, скорее в памяти в той или иной форме, Image, массив, или "напрямую" в памяти, но в принципе верно, тут формат записи не имеет особого значения. Важно одинаковые\разные.

Отредактировано Nigri_lupus (03.05.2023 21:55:46)

0

6

Nigri_lupus написал(а):

Почему же нет ответа - он есть.

В вашей голове возможно и есть.
Изначально в примере речь о сравнении двух файлов(и не важно что там внутри), затем выясняется что речь о памяти.
Вы в состоянии развёрнуто описать задачу в общем виде без терминов конкретного языка программирования и без допустим, а конкретно, что и для чего?

p.s. В любом случае всё на 99% сведётся к CompareMemory(*Buffer1, *Buffer2, Size) и обсуждать тут нечего.

Отредактировано useful (04.05.2023 06:12:28)

0


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Как сравнить две картинки с максимальной скоростью?