Jump to content

Remove White Spaces in image


 Share

Recommended Posts

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

 

#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 ()

 

 

 

test.png

croped.png

Edited by darkshark
Link to comment
Share on other sites

Reading directly from the bitmap is much faster:

#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).

 

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

24 minutes ago, UEZ said:

Reading directly from the bitmap is much faster:

#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).

 

UEZ

Thanks 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

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 here
RegExp tutorial: enough to get started
PCRE 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

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

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 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 here
RegExp tutorial: enough to get started
PCRE 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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...