Что нового

Разбиваем Bitmap на по пиксельную матрицу

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Написал код для разбиения картинки на пиксельную матрицу, применить данный пример практически негде, сегодня мне понадобилось сделать такую конструкцию и я решил выложить его здесь, буду рад советам по упрощению и оптимизации кода.

Код:
#include <GDIP.au3>
#include <GDIPlus.au3>
#include <Array.au3>

$Matrix = MatrixGetColor(@ScriptDir & '\Image1.png')
_ArrayDisplay($Matrix)

Func MatrixGetColor($sImage)
   
   Local $hImage, $iWidth, $iHeight, $iBitmap, $hBitmap
   
   _GDIPlus_Startup()
   $hImage = _GDIPlus_ImageLoadFromFile($sImage)
   $iWidth = _GDIPlus_ImageGetWidth($hImage)
   $iHeight = _GDIPlus_ImageGetHeight($hImage)
   $iBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
   $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($iBitmap)
   
   Dim $iMatrix[$iHeight][$iWidth]
   
   For $H = 0 To $iHeight - 1
      For $W = 0 To $iWidth - 1
	     $iMatrix[$H][$W] = '0x' & Hex(_GDIPlus_BitmapGetPixel($hBitmap, $W, $H), 6)
      Next
   Next
   
   _GDIPlus_ImageDispose($hImage)
   _WinAPI_DeleteObject($iBitmap)
   _WinAPI_DeleteObject($hBitmap)
   _GDIPlus_Shutdown()
   
   Return $iMatrix
EndFunc


Для работы необходима библиотека GDIP UDF
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если честно, то абсолютно бестолковый ход. Я конечно его не тестировал, но скорость должна быть "феноминальной".

Вообще, если у вас возникла необходимость переводить битмап в массив, то от этого сразу же нужно отказаться в пользу чего-нибудь другого. В крайнем случае использовать машинный код. Например, см. _WinAPI_IsAlphaBitmap() из WinAPEx.

Не подскажите, зачем вам понадобился массив?
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Да очень просто, я сам не сторонник такого хода, но меня попросили, есть возможность в Skype отправлять Html теги, вот и получается что можно таким образом отправить картинку:

Код:
<font color="#FEFEFE">#</font>

Получается что мы пишем # - почти белого цвета, но в Skype можно установить ещё и размер текста через тег и сделать пиксель белого цвета.

Если интересно. то вот пост на Хабрахабр на эту тему
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Тогда, я думаю, лучше сразу резать данные битмапа рег. выражениями в html код.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Чуть - чуть не понял, как это будет выглядеть? :scratch:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Код:
#Include <GDIPlus.au3>

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile(@ScriptDir & '\Image.png')
$Width = _GDIPlus_ImageGetWidth($hBitmap)
$Height = _GDIPlus_ImageGetHeight($hBitmap)
$tMap = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Width, $Height, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
$bData = DllStructGetData(DllStructCreate('byte[' & ($Width * $Height * 4) & ']', DllStructGetData($tMap, 'Scan0')), 1)
_GDIPlus_BitmapUnlockBits($hBitmap, $tMap)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_Shutdown()

ConsoleWrite($bData & @CR)


Остается как-то отформатировать эту строку с помощью рег. выражений в то, что нужно. Но я с ними не дружу.

:smile:
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
И на этом большое спасибо :smile: с рег. выражениями попробую позже разобратся :smile:
 

Ilyialat

Новичок
Сообщения
54
Репутация
2
ImageSearch работает медленней pixelsearch... Попробую разбить файл на массив и использовать PixelSearch =) Спасибо =)
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
Yashied
Остается как-то отформатировать эту строку с помощью рег. выражений в то, что нужно. Но я с ними не дружу.
Превращает строку в массив цветов пикселей, еще бы нужно координаты добавить...
Код:
#include <GDIPlus.au3>
#include <Array.au3>
#include <string.au3>
#include <Color.au3>

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile(@ScriptDir&'\test.jpg')
$Width = _GDIPlus_ImageGetWidth($hBitmap)
$Height = _GDIPlus_ImageGetHeight($hBitmap)
$tMap = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Width, $Height, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
$bData = DllStructGetData(DllStructCreate('byte[' & ($Width * $Height * 4) & ']', DllStructGetData($tMap, 'Scan0')), 1)
_GDIPlus_BitmapUnlockBits($hBitmap, $tMap)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_Shutdown()

ConsoleWrite($Width & ' '&$Height&@CR)
;ConsoleWrite($bData&@CR)
$bData=StringTrimLeft($bData&@CR, 2) 

$color=''
For $i = 1 To (StringLen($bData)) Step 8
$color=$color & '_' & StringMid($bData, $i, 8)
Next

$Array1=StringSplit($color,"_")
_ArrayDelete($Array1,0)
_ArrayDelete($Array1,0)
_ArrayDelete($Array1,Ubound($Array1)-1)
_ArrayTrim($Array1,2,1) 

For $i = 0 To Ubound($Array1)-1 
$Array1[$i]='0x'&Hex(_ColorGetBlue('0x'&$Array1[$i]),2) & Hex(_ColorGetGreen('0x'&$Array1[$i]),2) & Hex(_ColorGetRed('0x'&$Array1[$i]),2)
Next
_ArrayDisplay($Array1)

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

Yura

Знающий
Сообщения
36
Репутация
7
WSWR сказал(а):
Несколько переделал, и скорость возросла в пару десятков раз, однако, все еще не исключаю, что и это не самый быстрый вариант.

Возможно быстрее будет так:

Код:
Func img_get_colors2($img_name)
	_GDIPlus_Startup()
	$hBitmap = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\images\"&$img_name&".bmp") ; image location
	$Width = _GDIPlus_ImageGetWidth($hBitmap)
	$Height = _GDIPlus_ImageGetHeight($hBitmap)
	$tMap = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Width, $Height, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
	$bData = DllStructGetData(DllStructCreate('byte[' & ($Width * $Height * 4) & ']', DllStructGetData($tMap, 'Scan0')), 1)
	_GDIPlus_BitmapUnlockBits($hBitmap, $tMap)
	_GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()

	Local $aCol[$Height][$Width]
	For $i = 0 To $Height - 1
		For $j = 0 To $Width - 1
			$col_1 = StringMid($bData, 8*($j + $i*$Width) + 3, 2) ; color swap  
			$col_2 = StringMid($bData, 8*($j + $i*$Width) + 5, 2)
			$col_3 = StringMid($bData, 8*($j + $i*$Width) + 7, 2)
			$aCol[$i][$j] = "0x"&$col_3&$col_2&$col_1
			;$aCol[$i][$j] = "0x"&StringMid($bData, 8*($j + $i*$Width) + 3, 6) ; without color swap
		Next
	Next

	;_ArrayDisplay($aCol)
	Return($aCol)
EndFunc


Функция превращает строку в двухмерный массив цветов пикселей. Конвертация между RGB и BGR по выбору. Вывод в строку переделать тоже не проблема.
 
Верх