darkshark Posted December 11, 2016 Share Posted December 11, 2016 (edited) Hi, everyone! I have some pictures on my computer that I need to "remove the white parts". Basically I need to crop images only where it has some content ... I wrote this code that seems to work, but, it is very very slow ... I wonder if there is any other alternative to do this service! Attached I left the image used as test and what I expect result! If anyone could help me I would be very happy. Thank you very much expandcollapse popup#include <File.au3> #Include <GDIPlus.au3> Global $iMinX = 0 Global $iMinY = 0 Global $iMaxX = 0 Global $iMaxY = 0 _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\test.png") Local $iHeight = _GDIPlus_ImageGetHeight($hImage) Local $iWidth = _GDIPlus_ImageGetWidth($hImage) For $x = 0 To $iWidth For $y = 0 To $iHeight Local $iPixelColor = _GDIPlus_BitmapGetPixel($hImage, $x, $y) If $iPixelColor <> 4294967295 Then If $x < $iMinX or $iMinX = 0 Then $iMinX = $x EndIf If $x > $iMaxX Then $iMaxX = $x EndIf If $y < $iMinY or $iMinY = 0 Then $iMinY = $y EndIf If $y > $iMaxY Then $iMaxY = $y EndIf EndIf Next Next $hClone = _GDIPlus_BitmapCloneArea($hImage, $iMinY, $iMaxX, $iMaxY, $GDIP_PXF24RGB) _GDIPlus_ImageSaveToFile($hClone, @ScriptDir & "\croped.png") _GDIPlus_ImageDispose($hClone) _GDIPlus_ImageDispose($hImage) _GDIPlus_ShutDown () Edited December 11, 2016 by darkshark Link to comment Share on other sites More sharing options...
UEZ Posted December 11, 2016 Share Posted December 11, 2016 Reading directly from the bitmap is much faster: expandcollapse popup#include <File.au3> #Include <GDIPlus.au3> Global $iMinX = 0xFFFF Global $iMinY = 0xFFFF Global $iMaxX = 0 Global $iMaxY = 0 _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\test.png") Local $iHeight = _GDIPlus_ImageGetHeight($hImage) Local $iWidth = _GDIPlus_ImageGetWidth($hImage) Local $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iWidth, $iHeight, $GDIP_PXF01INDEXED) ;version darkshark Local $iPixelColor, $fTimer = TimerInit() For $x = 0 To $iWidth - 1 For $y = 0 To $iHeight - 1 $iPixelColor = _GDIPlus_BitmapGetPixel($hClone, $x, $y) If $iPixelColor = 4278190080 Then If $x < $iMinX Then $iMinX = $x If $y < $iMinY Then $iMinY = $y If $x > $iMaxX Then $iMaxX = $x If $y > $iMaxY Then $iMaxY = $y EndIf Next Next ConsoleWrite("Took " & Round(TimerDiff($fTimer), 2) & " ms." & @CRLF) Local $hCropped1 = _GDIPlus_BitmapCloneArea($hImage, $iMinX, $iMinY, $iMaxX - $iMinX + 1, $iMaxY - $iMinY + 1) _GDIPlus_ImageSaveToFile($hCropped1, @ScriptDir & "\cropped1.png") ;version reading directly from the bitmap $iMinX = 0xFFFF $iMinY = 0xFFFF $iMaxX = 0 $iMaxY = 0 $fTimer = TimerInit() Local $tBitmapData = _GDIPlus_BitmapLockBits($hClone, 0, 0, $iWidth, $iHeight) Local $tPixel = DllStructCreate("int[" & $iWidth * $iHeight & "];", DllStructGetData($tBitmapData, "Scan0")) Local $iRowOffset, $iPixel For $y = 0 To $iHeight - 1 $iRowOffset = $y * $iWidth + 1 For $x = 0 To $iWidth - 1 If DllStructGetData($tPixel, 1, $iRowOffset + $x) = 0xFF000000 Then If $x < $iMinX Then $iMinX = $x If $y < $iMinY Then $iMinY = $y If $x > $iMaxX Then $iMaxX = $x If $y > $iMaxY Then $iMaxY = $y EndIf Next Next _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData) ConsoleWrite("Took " & Round(TimerDiff($fTimer), 2) & " ms." & @CRLF) Local $hCropped2 = _GDIPlus_BitmapCloneArea($hImage, $iMinX, $iMinY, $iMaxX - $iMinX + 1, $iMaxY - $iMinY + 1) _GDIPlus_ImageSaveToFile($hCropped2, @ScriptDir & "\cropped2.png") _GDIPlus_ImageDispose($hClone) _GDIPlus_ImageDispose($hImage) _GDIPlus_ImageDispose($hCropped1) _GDIPlus_ImageDispose($hCropped2) _GDIPlus_ShutDown () The fastest solution is using inline assembler which I don't want to code now 'cause it's too late here (11pm). darkshark 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
darkshark Posted December 11, 2016 Author Share Posted December 11, 2016 24 minutes ago, UEZ said: Reading directly from the bitmap is much faster: expandcollapse popup#include <File.au3> #Include <GDIPlus.au3> Global $iMinX = 0xFFFF Global $iMinY = 0xFFFF Global $iMaxX = 0 Global $iMaxY = 0 _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\test.png") Local $iHeight = _GDIPlus_ImageGetHeight($hImage) Local $iWidth = _GDIPlus_ImageGetWidth($hImage) Local $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iWidth, $iHeight, $GDIP_PXF01INDEXED) ;version darkshark Local $iPixelColor, $fTimer = TimerInit() For $x = 0 To $iWidth - 1 For $y = 0 To $iHeight - 1 $iPixelColor = _GDIPlus_BitmapGetPixel($hClone, $x, $y) If $iPixelColor = 4278190080 Then If $x < $iMinX Then $iMinX = $x If $y < $iMinY Then $iMinY = $y If $x > $iMaxX Then $iMaxX = $x If $y > $iMaxY Then $iMaxY = $y EndIf Next Next ConsoleWrite("Took " & Round(TimerDiff($fTimer), 2) & " ms." & @CRLF) Local $hCropped1 = _GDIPlus_BitmapCloneArea($hImage, $iMinX, $iMinY, $iMaxX - $iMinX + 1, $iMaxY - $iMinY + 1) _GDIPlus_ImageSaveToFile($hCropped1, @ScriptDir & "\cropped1.png") ;version reading directly from the bitmap $iMinX = 0xFFFF $iMinY = 0xFFFF $iMaxX = 0 $iMaxY = 0 $fTimer = TimerInit() Local $tBitmapData = _GDIPlus_BitmapLockBits($hClone, 0, 0, $iWidth, $iHeight) Local $tPixel = DllStructCreate("int[" & $iWidth * $iHeight & "];", DllStructGetData($tBitmapData, "Scan0")) Local $iRowOffset, $iPixel For $y = 0 To $iHeight - 1 $iRowOffset = $y * $iWidth + 1 For $x = 0 To $iWidth - 1 If DllStructGetData($tPixel, 1, $iRowOffset + $x) = 0xFF000000 Then If $x < $iMinX Then $iMinX = $x If $y < $iMinY Then $iMinY = $y If $x > $iMaxX Then $iMaxX = $x If $y > $iMaxY Then $iMaxY = $y EndIf Next Next _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData) ConsoleWrite("Took " & Round(TimerDiff($fTimer), 2) & " ms." & @CRLF) Local $hCropped2 = _GDIPlus_BitmapCloneArea($hImage, $iMinX, $iMinY, $iMaxX - $iMinX + 1, $iMaxY - $iMinY + 1) _GDIPlus_ImageSaveToFile($hCropped2, @ScriptDir & "\cropped2.png") _GDIPlus_ImageDispose($hClone) _GDIPlus_ImageDispose($hImage) _GDIPlus_ImageDispose($hCropped1) _GDIPlus_ImageDispose($hCropped2) _GDIPlus_ShutDown () The fastest solution is using inline assembler which I don't want to code now 'cause it's too late here (11pm). UEZThanks a lot for the help, really doing it this way is much faster!I really would not be able to do it in assembly since I do not know anything about that language.I'll use this code you sent me!Thank you and good night! Link to comment Share on other sites More sharing options...
jchd Posted December 11, 2016 Share Posted December 11, 2016 It's as late here but if your source image is always a rectangle horizontally centered (or anything close to that) you can certainly remain within AutoIt to speed this up by a factor. Test center pixel of the image line by line until you encounter <something which isn't white enough> This is the top line of the rectangle. From there test pixels on the same line until you hit <something which is white enough> on the left (leftmost column) and then on the right (rightmost column). From there test pixels on the same (rightmost) column until you hit <something which is white enough> and you have the bottom line of the bounding rectangle of your picture. Adjust <colour match values> to something good enough for your actual use cases. This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
darkshark Posted December 11, 2016 Author Share Posted December 11, 2016 5 minutes ago, jchd said: It's as late here but if your source image is always a rectangle horizontally centered (or anything close to that) you can certainly remain within AutoIt to speed this up by a factor. Test center pixel of the image line by line until you encounter <something which isn't white enough> This is the top line of the rectangle. From there test pixels on the same line until you hit <something which is white enough> on the left (leftmost column) and then on the right (rightmost column). From there test pixels on the same (rightmost) column until you hit <something which is white enough> and you have the bottom line of the bounding rectangle of your picture. Adjust <colour match values> to something good enough for your actual use cases. Thanks for the answer, I understood your reasoning, but not always an image will be a rectangle, sometimes it will have text, some other image ... Link to comment Share on other sites More sharing options...
jchd Posted December 11, 2016 Share Posted December 11, 2016 (edited) Ha, much harder then. I was focused on the test case you submitted. Yet you can enhance UEZ' code significantly. Redeclare the bitmap DllStruct as a 2D array, then if your background is homogenously white (or some fixed color) then just compare successive rows until the last one differs, giving the top. Do the same for the bottom, comparing rows upwards. That saves a lot of comparisons. EDIT: I just tried some code implementing the idea but forget it. That won't work reliably as I discovered that the image is heavily watermarked. Edited December 12, 2016 by jchd This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
UEZ Posted December 12, 2016 Share Posted December 12, 2016 Btw, the images above don't have a homogene white background, thus you cannot check easily for 0xFFFFFFFF. That's the reason using 1-bit images. Of course this method might not be very precise because you cannot set the threshold of white/black. Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now