Página 1 de 1

Ayuda con Raw Data Pixel

Publicado: 25 May 2011, 00:14
por ms999
Hola foro como van a ver el tema de la imagen binaria quedo colgado por ahi, pero me segui interezando acerca de como obtener datos de un BMP.. empece investigando la funcion LockBits y vi en MSDN que era un metodo..
primera pregunta ¿en que se diferencia un metodo a una funcion?

Bueno estube dando vueltas y pude hacer andar la funcion y me devolvia una estructura... de ahi a saber como usar esos datos para sacar los datos de los colores en cada pixel no pude... vi que habia ejemplos en MSDN pero escritos en C++ y VB.NET pero no pude interpretar ninguno para pasarlos a autoit.

Luego se me dio por buscar en el foro de AutoIt y encontre la la manera de hacerlo gracias a un usuario de ahi que posteo un script que hacie exactamente eso.. en esta funcion tengo un par de dudas que luego les aclarare aver si me ayudan a entender algo(luego lo pongo con mis agregados)

Bueno a esa funcion le agregue otra para seleccionar un area y que tome una screen de la seleccion, tambien me ayudaron en el foro de AutoIt oficial... (siempre bien encaminado pero nunca pude definirlo solo ..)

Y use la funcion que habiamos echo con el proyecto de la imagen binaria para imprimir el arreglo de colores en un control grafico(no uso este metodo por lo practico sino que es para imprimir a partir de un arreglo)

tengo este script que ademas tienen unos marcadores de tiempo para chekear cuanto tarda cada etapa en realizarse...

Código: Seleccionar todo

#include <misc.au3>
#include <WindowsConstants.au3>
#include <winapi.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
HotKeySet("{esc}", "_exit")
Global $pos
$Gui = GUICreate("selection tool", 300, 50, -1, -1)
$bnSelect = GUICtrlCreateButton("start select", 0, 0, 100, 50)
$bnShowRaw = GUICtrlCreateButton("ShowRawData", 100, 0, 100, 50)
GUICtrlSetState($bnShowRaw, $GUI_DISABLE)
$bnShowFromRD = GUICtrlCreateButton("ShowScrenfromRD", 200, 0, 100, 50)
GUICtrlSetState($bnShowFromRD, $GUI_DISABLE)
GUISetState()
While 1
	$nmsg = GUIGetMsg()
	Switch $nmsg
		Case -3
			_exit()
		Case $bnSelect
			$sel = _drawbox()
			If IsArray($sel) Then
				GUICtrlSetState($bnShowRaw, $GUI_ENABLE)
			EndIf
		Case $bnShowRaw
			$begin1 = TimerInit()
			$rawdata = _Getrawdata($sel[4])
			If Not @error Then
				ConsoleWrite("Time in ms to do all the work = " & TimerDiff($begin1) & @CRLF)
				GUICtrlSetState($bnShowFromRD, $GUI_ENABLE)
                                _arraydisplay($rawdata)
			EndIf
		Case $bnShowFromRD
			$ShowGUI = GUICreate("screen show", $sel[2], $sel[3], $sel[0], $sel[1], $WS_POPUP)
			$graph = GUICtrlCreateGraphic(0, 0, $sel[2], $sel[3])
			_printrawdata($rawdata, $graph)
			GUISetState(@SW_SHOW, $ShowGUI)
			GUICtrlSetState($graph, $GUI_SHOW)
			MsgBox(0, "tip", "Press ´BackSpace´key to close Show window")
			Do
				Sleep(50)
			Until _IsPressed("08") ; BackSpace
			GUIDelete($ShowGUI)
	EndSwitch
WEnd
Func _Exit()
	Exit
EndFunc   ;==>_Exit
Func _drawbox()
	$hGui = GUICreate("selectionbox", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
	GUISetBkColor(0x000000, $hGui)
	WinSetTrans($hGui, "", 20)
	GUISetState()
	GUISetCursor(3)
	$DLL = DllOpen("user32.dll")
	While Not _IsPressed("01", $DLL)
		$pos = MouseGetPos()
		Sleep(10)
	WEnd
	$iX = $pos[0]
	$iW = 0
	$iY = $pos[1]
	$iH = 0
	While _IsPressed(01, $DLL)
		$pos2 = MouseGetPos()
		Select
			Case $pos2[0] < $pos[0]
				$iX = $pos2[0]
				$iW = $pos[0] - $pos2[0]
			Case $pos[0] < $pos2[0]
				$iX = $pos[0]
				$iW = $pos2[0] - $pos[0]
		EndSelect
		Select
			Case $pos2[1] < $pos[1]
				$iY = $pos2[1]
				$iH = $pos[1] - $pos2[1]
			Case $pos[1] < $pos2[1]
				$iY = $pos[1]
				$iH = $pos2[1] - $pos[1]
		EndSelect
		_GUICreateInvRect($hGui, $iX, $iY, $iW, $iH)
	WEnd
	GUIDelete($hGui)
	DllClose($DLL)
	$begin = TimerInit()
	$hBMP = _ScreenCapture_Capture("", $iX, $iY, $iW + $iX, $iH + $iY)
	ConsoleWrite("Time in ms. to take a screen from a " & $iW & "X" & $iH & " Area = " & TimerDiff($begin) & @CRLF)
	Local $selectedpos[5] = [$iX, $iY, $iW, $iH, $hBMP]
	Return $selectedpos
EndFunc   ;==>_drawbox

Func _GUICreateInvRect($hWnd, $iX, $iY, $iW, $iH)
	$hMask_1 = _WinAPI_CreateRectRgn(0, 0, @DesktopWidth, $iY)
	$hMask_2 = _WinAPI_CreateRectRgn(0, 0, $iX, @DesktopHeight)
	$hMask_3 = _WinAPI_CreateRectRgn($iX + $iW, 0, @DesktopWidth, @DesktopHeight)
	$hMask_4 = _WinAPI_CreateRectRgn(0, $iY + $iH, @DesktopWidth, @DesktopHeight)
	_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_2, 2)
	_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_3, 2)
	_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_4, 2)
	_WinAPI_DeleteObject($hMask_2)
	_WinAPI_DeleteObject($hMask_3)
	_WinAPI_DeleteObject($hMask_4)
	_WinAPI_SetWindowRgn($hWnd, $hMask_1, 1)
EndFunc   ;==>_GUICreateInvRect
Func _Getrawdata($hBMP) ; Credits to Malkey http://www.autoitscript.com/forum/index.php?app=forums&module=forums&section=findpost&pid=718522
	_GDIPlus_Startup()
	$hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
	$width = _GDIPlus_ImageGetWidth($hBitmap)
	$height = _GDIPlus_ImageGetHeight($hBitmap)
	Local $aSize = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', 0, 'ptr', 0)
	If Not @error Then
		$tBits = DllStructCreate('byte[' & $aSize[0] & ']')
		$begin = TimerInit()
		DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBMP, 'int', $aSize[0], 'ptr', DllStructGetPtr($tBits))
		$sHex = Hex(DllStructGetData($tBits, 1))
		ConsoleWrite("Time in ms. to get the rawdata and save it in a variable = " & TimerDiff($begin) & @CRLF)
		$begin = TimerInit()
		$sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
		Local $pix[$height][$width], $aTemp
		$aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
		ConsoleWrite("Time in ms to preparate the rawdata to be indexed in an array = " & TimerDiff($begin) & @CRLF)
		$begin = TimerInit()
		For $width = 0 To UBound($aArr) - 1
			$aTemp = StringRegExp($aArr[$width] & " ", "(.{6}) ", 3)
			For $height = 0 To UBound($aTemp) - 1
				$pix[$width][$height] = StringRegExpReplace($aTemp[$height], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
			Next
		Next
		ConsoleWrite("Time in ms to put the entire raw in an array = " & TimerDiff($begin) & @CRLF)
	Else
		SetError(@error)
		Return ""
	EndIf
	_GDIPlus_BitmapDispose($hBitmap)
	_WinAPI_DeleteObject($hBMP)
	_GDIPlus_Shutdown()
	Return $pix
EndFunc   ;==>_Getrawdata
Func _printrawdata($ArBMPRawdata, $hgraphic)
	$begin = TimerInit()
	For $x = 0 To UBound($ArBMPRawdata) - 1
		For $y = 0 To UBound($ArBMPRawdata, 2) - 1
			$color = "0x" & $ArBMPRawdata[$x][$y]
			GUICtrlSetGraphic($hgraphic, $GUI_GR_COLOR, $color)
			GUICtrlSetGraphic($hgraphic, $GUI_GR_PIXEL, $y, $x) ; :S
			GUICtrlSetState($graph, $GUI_SHOW)
		Next
	Next
	ConsoleWrite("Time in ms to print from the rawdata using GuictrlsetGraphics = " & TimerDiff($begin) & @CRLF)
EndFunc   ;==>_printrawdata
Mi primer duda seria en esta parte

Código: Seleccionar todo

$sHex = Hex(DllStructGetData($tBits, 1))
		$sHex = StringRegExpReplace($sHex, "([[:xdigit:]]{6})(FF)", "\1 ")
		Local $pix[$height][$width], $aTemp
		$aArr = StringRegExp($sHex, "(.{" & ($width * 7) & "})", 3)
		For $width = 0 To UBound($aArr) - 1
			$aTemp = StringRegExp($aArr[$width] & " ", "(.{6}) ", 3)
			For $height = 0 To UBound($aTemp) - 1
				$pix[$width][$height] = StringRegExpReplace($aTemp[$height], "(.{2})(.{2})(.{2})", "\3\2\1") ; To RGB format
			Next
		Next
Si alguien me aclara un poco como es que esta separando toda la data para acomodarla en un arreglo se lo agradeceria..

Lo otro que era por lo que principalmente venia esta relacionado con esto anterior...
La parte que mas tarda en realizar el programa es acomodar los datos en un arreglo... ¿que metodo me proponen para evitar esto y buscar directamente un pixel de tal coordenada a partir del dato principal sin ponerlo en un arreglo?

Desde ya gracias y no tienen la obligacion de contestar, solo si les interezo el tema

EDIT: Le agregue un _arraydisplay() para que vean los resultados en una tabla

Y tambien les agrego los resultados de mi "banco de prueba" para que vean lo que tarda cada etapa del programa algunos datos no me sorprenden tanto... yo sabia que Getpixel x pixel no era la manera de hacerlo si los datos estan en memoria debe ser rapido recuperarlos.. :smt035

Código: Seleccionar todo

>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "F:\Agustin\autoit\Foro Autoit\selection Box.au3" /autoit3dir "C:\Program Files (x86)\AutoIt3" /UserParams    
+>19:15:50 Starting AutoIt3Wrapper v.2.0.1.24    Environment(Language:0C0A  Keyboard:0000040A  OS:WIN_7/  CPU:X64 OS:X64)
>Running AU3Check (1.54.19.0)  from:C:\Program Files (x86)\AutoIt3
+>19:15:50 AU3Check ended.rc:0
>Running:(3.3.6.1):C:\Program Files (x86)\AutoIt3\autoit3_x64.exe "F:\Agustin\autoit\Foro Autoit\selection Box.au3"    
Time in ms. to take a screen from a 1679X1049 Area = 169.281363649551
Time in ms. to get the rawdata and save it in a variable = 350.138662051994
Time in ms to preparate the rawdata to be indexed in an array = 6982.95608722142
Time in ms to put the entire raw in an array = 52866.9062746925
Time in ms to do all the work = 60251.2221886589
PD: Otra cosa que voy a empezar a ver es como armar un BMP, a partir del arreglo este... aunque windows tiene funciones para hacer esto...
PD2: El Script esta en ingles porque estube trabajando con gente del foro de AutoIt en ingles...
PD3: Ojo si prueban mostrar la imagen a travez de la raw data si la imagen que tomaron es muy grande... se les puede colgar la PC.... yo todabia y hace 3 min estoy esperando los resultados de la full screen ... pero esto solo si lo que quieren es mostrarla para tomar los datos y ver el arreglo esta todo mas que bien.