Jump to content
dejhost

Extracting color-values of image along a user specified line

Recommended Posts

Happy New Year everyone!

I would like to extract the color values of certain pixels in an image.  This is how I picture the workflow: 

  1. User opens an image of his choice. Image is shown on the screen.
  2. User draws a line into the image. This happens by marking the startpixel and the endpixel of the line
  3. The line is drawn, so the user can check visually if he is happy with the line.
  4.  The following pixel based properties belonging to the line are stored in Excel:
    1. X-Coordinate
    2. Y-Coordinate
    3. Color Value
  5. Additional operations: Extracting for max- and min. color values; Statistical operations.  

Browsing through the helpfile of AutoIt I find plenty of functions for treating images (e.g. GDIPlus), but I am completely unsure if Autoit will get me there. Should I read the entire image into an array? Should I rather attempt to script an external image software (e.g. IrfanView, Gimp)?

I would be very thankful if someone could give some recommendations and maybe list a couple of the most important commands to use.

Thank you very much.

Dejhost

 

 

Share this post


Link to post
Share on other sites

Hello again,

documenting roughly what I've done so far:

  • Open image: 
_GDIPlus_ImageLoadFromFile 

But how to retrieve the pixel-coordinates that the line covers? Is there a way to get a 2D-array?

Afterward, I would use the following function to get the pixel colors:

_GDIPlus_BitmapGetPixel

Thanks in advance for any advice!

Edited by dejhost
grammar

Share this post


Link to post
Share on other sites

Yes it is totally doable with GDI+.  There are a few examples in the help file that are somewhat close to what you want to create.  The functions that you mentioned will certainly be part of the solution...To get the pixel, you will probably have to use some of the basic geometry that you learned in HS.

Happy scripting !

Edited by Nine

Share this post


Link to post
Share on other sites

Thank you for your encouraging words. So at least I am on the right track :-)

If I have to rely on my HS-memories, the result would not be accurate: I recall that there are plenty of ways to connect 2 points based on pixels. I'd rather use the same method for retrieving the pixel coordinates as the AutoIt uses for drawing the line:

Within the GDIPlus.au3, I find the function

_GDIPlus_GraphicsDrawLine

calls for a dll:

Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipDrawImageRectRect", "handle", $hGraphics, "handle", $hImage, _
            "float", $nDstX, "float", $nDstY, "float", $nDstWidth, "float", $nDstHeight, _
            "float", $nSrcX, "float", $nSrcY, "float", $nSrcWidth, "float", $nSrcHeight, _
            "int", $iUnit, "handle", $pAttributes, "ptr", 0, "ptr", 0)

I will try to track down this dll. Hoping it is so kind to tell me how it draws lines :-)

Share this post


Link to post
Share on other sites
10 hours ago, Nine said:

nn for that complex dllcalll.  dont over-complex your script when you can do it with std func.

What do you mean by "std func"? Standard functions?

If you know a function that could suit, please share. thx.

Edited by dejhost

Share this post


Link to post
Share on other sites
3 hours ago, dejhost said:

What do you mean by "std func"? Standard functions?

Yes here to start you up :

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WinAPIHObj.au3>
#include <Color.au3>

Global $g_hGUI, $g_hGfxCtxt, $g_hBitmap, $g_hBMP, $g_hGraphics
Global $aCursA, $aCursB, $Completed = False

    AutoItSetOption("GUIOnEventMode", 1)

    _GDIPlus_Startup()

    $g_hBMP = _GDIPlus_BitmapCreateFromFile ("BaseImage.jpg")
    Global $iWidth = _GDIPlus_ImageGetWidth ($g_hBMP), $iHeight = _GDIPlus_ImageGetHeight ($g_hBMP)

    $g_hGUI = GUICreate("GDI+", $iWidth, $iHeight+100)
    $idButton = GUICtrlCreateButton ("Completed", int($iWidth/2)-100, $iHeight+30, 200, 50)
    GUICtrlSetOnEvent(-1, "Complete")

    GUISetState(@SW_SHOW)

    $g_hGraphics = _GDIPlus_GraphicsCreateFromHWND($g_hGUI) ;create a graphics object from a window handle
    $g_hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $g_hGraphics)
    $g_hGfxCtxt = _GDIPlus_ImageGetGraphicsContext($g_hBitmap)

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    _GDIPlus_GraphicsDrawImage($g_hGfxCtxt, $g_hBMP, 0, 0) ;draw bitmap to backbuffer

    Do
        _GDIPlus_GraphicsDrawImageRect($g_hGraphics, $g_hBitmap, 0, 0, $iWidth, $iHeight) ;copy drawn bitmap to graphics handle (GUI)
        $aCursA = GUIGetCursorInfo ($g_hGUI)
        if @error then ContinueLoop
        $aCursB = $aCursA
        Local $iX = -1, $iY = -1

        While $aCursB[2] and $aCursB[0] <= $iWidth and $aCursB[1] <= $iHeight
          $aCursB = GUIGetCursorInfo ($g_hGUI)
          if $iX = $aCursB[0] and $iY = $aCursB[1] then ContinueLoop
          $iX = $aCursB[0]
          $iY = $aCursB[1]
          _GDIPlus_GraphicsClear($g_hGfxCtxt, 0xFF000000) ;clear bitmap for repaint
          _GDIPlus_GraphicsDrawImage($g_hGfxCtxt, $g_hBMP, 0, 0)
          _GDIPlus_GraphicsDrawImageRect($g_hGraphics, $g_hBitmap, 0, 0, $iWidth, $iHeight)
          _GDIPlus_GraphicsDrawLine($g_hGraphics, $aCursA[0], $aCursA[1], $aCursB[0], $aCursB[1])
          _GDIPlus_GraphicsDrawLine($g_hGfxCtxt, $aCursA[0], $aCursA[1], $aCursB[0], $aCursB[1])
        Wend

        Sleep (100)

    Until $Completed


    _Exit ()

Func Complete ()

  $Completed = True

EndFunc

Func _Exit()

  _GDIPlus_GraphicsDispose($g_hGfxCtxt)
  _GDIPlus_GraphicsDispose($g_hGraphics)
  _GDIPlus_BitmapDispose($g_hBitmap)
  _GDIPlus_BitmapDispose($g_hBMP)
  _GDIPlus_Shutdown()
  GUIDelete($g_hGUI)

EndFunc

 

Share this post


Link to post
Share on other sites

This _PixelsInLineToArray function will calculate the "x" or "y" value from the equation of a straight line of two points.

Example:- If the two points are pt1(10,10) and pt2(13, 30) then the "y" values are used to calculate the 21 "x" values. (The difference in "y" values is greater than the difference in "x" values.)  This will return 21 x, y, and pixel colours in the array.
If the "x" values were used, there would only be 4 calculations made from 10 to 13, which would return a 4 element array.  

#include <Array.au3>
#include <WinAPIGdi.au3>

; Using $scale in position calculations is sometimes necessary when, under the system's
; "Display" settings, the "Scale and layout" parameter is not 100%.
; When the "Scale and layout" parameter is 100%, this $scale value = 1.
Global $scale = _WinAPI_EnumDisplaySettings('', $ENUM_CURRENT_SETTINGS)[0] / @DesktopWidth

Local $Pt1[2] = [52, 28]
Local $Pt2[2] = [50, 60]
_ArrayDisplay(_PixelsInLineToArray($Pt1[0], $Pt1[1], $Pt2[0], $Pt2[1]))


; Parameters:-
;             $Pt1X, $Pt1Y - are the x and y coordinates of point 1
;             $Pt2X, $Pt2Y - are the x and y coordinates of point 2
; Returns: A 2D array:-
;                      $aArray[0] contains the X coordinate of the pixel
;                      $aArray[1] contains the Y coordinate of the pixel
;                      $aArray[3] contains the colour of the pixel in 0xRRGGBB 24bit hex. colour format. (This is what PixelGetColor returns)
;                          Where, "RR" (0-255) Red channel, "GG" (0-255) Green channel, "BB" (0-255) Blue channel.
;                          For 32bit GDIPlus hex colour format is 0xAARRGGBB.  Where. "AA" (0-255) is Alpha channel (transparency).
;                          Examples of 0xRRGGBB 24bit hex. colour format:- 0xFFFFFF is white, 0x000000 is black, 0xFF0000 is red, 0x00FF00 is green.
;
Func _PixelsInLineToArray($Pt1X, $Pt1Y, $Pt2X, $Pt2Y)
    If Abs($Pt1X - $Pt2X) > Abs($Pt1Y - $Pt2Y) Then
        If $Pt1X > $Pt2X Then ; If Abs($Pt1X - $Pt2X) has the greater distance, make Point 2 "x" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line

        Local $aArray[($Pt2X - $Pt1X) + 1][3]
        For $x = $Pt1X To $Pt2X ; Note: $Pt2X has a greater value than $Pt1X.
            $aArray[$x - $Pt1X][0] = $x
            $aArray[$x - $Pt1X][1] = Round(($m * $x) - ($m * $Pt1X) + $Pt1Y, 0) ; y = $m(x - x1) + y1  (y value from equation for a straight line)
            $aArray[$x - $Pt1X][2] = "0x" & Hex(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale), 6)
        Next
        Return $aArray
    Else
        If $Pt1Y > $Pt2Y Then ; If Abs($Pt1Y - $Pt2Y) has the greater distance, make Point 2 "y" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient

        Local $aArray[$Pt2Y - $Pt1Y + 1][3]
        For $y = $Pt1Y To $Pt2Y ; Note: $Pt2Y has a greater value than $Pt1Y
            $aArray[$y - $Pt1Y][0] = Round(($y / $m) - ($Pt1Y / $m) + $Pt1X, 0) ; x = (y - y1)/$m + x1 (x value from equation for a straight line)
            $aArray[$y - $Pt1Y][1] = $y
            $aArray[$y - $Pt1Y][2] = "0x" & Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6)
        Next
        Return $aArray
    EndIf
EndFunc   ;==>_PixelsInLineToArray

 

Share this post


Link to post
Share on other sites

I used "UEZ" tool "show Histogram" as a starting point for my approach:  https://bit.ly/2GXZMZ9. The histograms are a "nice to have" feature for me, and everything is nicely done. 

I am about to implement "Bresenham's line algorithm" (https://bit.ly/2RGh2Gx) to get the pixels in the line. Once done, I will implement drawing the line based on the points in the array - and then compare our results with one another. I will come back to you soon.

 

 

 

 

Share this post


Link to post
Share on other sites

Hello Malkey,

I realized by now that you implemented the Bresenham's formula. :-)   I used the function

For $k = 1 to UBound($aArray,1)-1 Step 1
    _GDIPlus_GraphicsFillRect( $hGraphics, $aArray[$k][0],  $aArray[$k][1], 1,1 )
Next

to draw the line from the array - just as a visual control. It seems correct.

But I struggle with the color code, although you have inserted a nice description:

Quote

 Where, "RR" (0-255) Red channel, "GG" (0-255) Green channel, "BB" (0-255) Blue channel.
;                          For 32bit GDIPlus hex colour format is 0xAARRGGBB.  Where. "AA" (0-255) is Alpha channel (transparency).
;                          Examples of 0xRRGGBB 24bit hex. colour format:- 0xFFFFFF is white, 0x000000 is black, 0xFF0000 is red, 0x00FF00 is green.
 

I am currently only treating grayscale images. So in case, the user opens a color image, it will get converted to grayscale prior analysis.*

In this case, the values for R, G and B are identical. So the information I am looking for is actually contained in each channel. My goal is to get the gray values in a scale of 0-255. So, hexadecimal is not the right format for my purposes. This is why I changed your code from

$aArray[$y - $Pt1Y][2] = "0x" & Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6)

 to

$aArray[$y - $Pt1Y][2] = StringRight(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale),2)

How do I proceed? How to apply the scale that I am looking for?

Thank you all for your support!

 

 

*I read in an post that the grayscale conversion by GDIPLUS is not very good. The post was quite old - did the function improve? Would you recommend to use another program to perform the conversion? I could send a command to IrfanView, for example....

 

 

Share this post


Link to post
Share on other sites

See the comments in the attached example about the color channel's value.  

To address your concerns about grayscale conversion quality, see the example under the _GDIPlus_ColorMatrixCreateGrayScale function in the AutoIt help file. 

; This gets the 24 bit pixel colour in  hex. colour format 0xRRGGBB
; These three separate colour channels, Red, Green, and Blue each range hexadeciminally from "00" to "FF" (0-255).
ConsoleWrite("0x" & Hex(PixelGetColor(100, 150), 6) & @CRLF) ; Example return 0xF0F4F9

; This gets the pixel's far right 8 bit colour channel, Blue, in hexadeciminal (base 16).
ConsoleWrite("0x" & StringRight(Hex(PixelGetColor(100, 150), 6), 2) & @CRLF) ; Example return 0xF9

; This gets the pixel's far right 8 bit colour channel, Blue, in deciminal (base 10).
ConsoleWrite(Dec(StringRight(Hex(PixelGetColor(100, 150), 6), 2)) & @CRLF) ; Example return 249

; Replacement line for script.
; $aArray[$y - $Pt1Y][2] = Dec(StringRight(Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6), 2))

 

Edited by Malkey
Added link to _GDIPlus_ColorMatrixCreateGrayScale

Share this post


Link to post
Share on other sites

Thank you very much! Works like a charm :D

I am using _GDIPlus_ColorMatrixCreateGrayScale - function. The GDIPlus.au3 calls a dll - meaning I can't track down how the matrix is setup. Would be nice to know how the red-, green- and blue channels get weighted during the conversion.

But I can compare with the results of GDIPlus and IrfanView at a later stage.

---

 

As I mentioned earlier, I use _GDIPlus_GraphicsDrawLine and _GDIPlus_GraphicsFillRect to draw lines. These lines are drawn on top of an image  that I opened with _GDIPlus_GraphicsDrawImageRectRect.

Applying the function _GDIPlus_ImageSaveToFile does not save the line along with the image - only the original image itself. In order to get a snapshot of both, image and line, I've used a workaround so far: I am taking a screenshot with autoit. But the soution not very convenient and fails easily. Is there a more elegant way to save image and line together in a jpg?

 

 

 

 

Share this post


Link to post
Share on other sites

When this example first starts the values in the 5x5 gray-scale color matrix are displayed.

To use this example:- 
Press left mouse button down, drag and move the mouse, then release the left mouse button to draw a line.
Press middle mouse button or Ctrl key to clear lines,
Press Alt+"s" to save the image with the last line drawn. 

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
#include <WinAPIHObj.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <Misc.au3>

Global $scale = _WinAPI_EnumDisplaySettings('', $ENUM_CURRENT_SETTINGS)[0] / @DesktopWidth

Example()

Func Example()
    Local $dll = DllOpen("user32.dll"), $aMPosNew
    If Not FileExists(@ScriptDir & "\cmy-circles.jpg") Then _
            InetGet("http://www.epi-centre.com/basics/color/images/cmy-circles.jpg", _
            @ScriptDir & "\cmy-circles.jpg")

    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\cmy-circles.jpg")
    Local $iWidth = _GDIPlus_ImageGetWidth($hImage)
    Local $iHeight = _GDIPlus_ImageGetHeight($hImage)

    Local $hGUI = GUICreate("GDI+ Example (" & @ScriptName & ")", $iWidth, $iHeight, 10, 10, $WS_POPUP) ;create a test GUI
    GUISetState(@SW_SHOW)

    Local $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;create a graphics object from a window handle
    Local $hBM = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphicGUI) ;create a Bitmap object based on a graphics object
    Local $hGraphicBM = _GDIPlus_ImageGetGraphicsContext($hBM) ;get the graphics context of the image / bitmap to draw on image / bitmap

    _GDIPlus_GraphicsSetSmoothingMode($hGraphicBM, $GDIP_SMOOTHINGMODE_HIGHQUALITY) ;sets the graphics object rendering quality (antialiasing)

    Local $hIA = _GDIPlus_ImageAttributesCreate() ;create an ImageAttribute object
    Local $tColorMatrix = _GDIPlus_ColorMatrixCreateGrayScale() ;create greyscale color matrix
    _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $tColorMatrix) ;set greyscale color matrix

    _GDIPlus_GraphicsClear($hGraphicBM, 0xFF000000)
    _GDIPlus_GraphicsDrawImageRectRect($hGraphicBM, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA) ;draw the bitmap while applying the color adjustment
    _GDIPlus_GraphicsDrawImageRect($hGraphicGUI, $hBM, 0, 0, $iWidth, $iHeight)
    Local $hPen = _GDIPlus_PenCreate(0xffff0000, 2)

    _DisplayColorMatrix($tColorMatrix)

    Do
        Select
            Case _IsPressed("01", $dll) ; Left mouse button down - Drag and move mouse - Release left mouse button to draw a line
                If WinExists("Pixels", "") Then WinClose("Pixels", "")
                $aMPos = MouseGetPos()
                Do
                    Sleep(10)
                Until Not _IsPressed("01", $dll)
                $aMPosNew = MouseGetPos()
                Local $aArr = _PixelsInLineToArray($aMPos[0], $aMPos[1], $aMPosNew[0], $aMPosNew[1])
                If UBound($aArr) > 1 Then
                    _GDIPlus_GraphicsDrawLine($hGraphicGUI, $aMPosNew[0], $aMPosNew[1], $aMPos[0], $aMPos[1], $hPen)
                    _ArrayDisplay($aArr, "Pixels")
                EndIf
            Case _IsPressed("04", $dll) Or _IsPressed("11", $dll) ; Press middle mouse button, or, Ctrl key to clear lines
                _GDIPlus_GraphicsClear($hGraphicBM)
                _GDIPlus_GraphicsClear($hGraphicGUI)
                _GDIPlus_GraphicsDrawImageRectRect($hGraphicBM, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA) ;draw the bitmap while applying the color adjustment
                _GDIPlus_GraphicsDrawImageRect($hGraphicGUI, $hBM, 0, 0, $iWidth, $iHeight)
            Case _IsPressed("12", $dll) And _IsPressed("53", $dll) ; Press Alt + "s" to save image
                _GDIPlus_GraphicsDrawLine($hGraphicBM, $aMPosNew[0], $aMPosNew[1], $aMPos[0], $aMPos[1], $hPen)
                _GDIPlus_ImageSaveToFile($hBM, @ScriptDir & "\SCTesta.jpg")
                ShellExecuteWait(@ScriptDir & "\SCTesta.jpg")

        EndSelect
    Until GUIGetMsg() = $GUI_EVENT_CLOSE

    ;cleanup GDI+ resources
    _GDIPlus_ImageAttributesDispose($hIA)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _GDIPlus_GraphicsDispose($hGraphicBM)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_BitmapDispose($hBM)
    _GDIPlus_Shutdown()
    GUIDelete($hGUI)
EndFunc   ;==>Example

Func _DisplayColorMatrix($tCMStruct) ; See $tagGDIPCOLORMATRIX AutoIt Help File
    Local $aArray[5][5]
    For $i = 1 To 5
        For $j = 1 To 5
            $aArray[$i - 1][$j - 1] = DllStructGetData($tCMStruct, 1, (($i - 1) * 5) + $j)
        Next
    Next
    _ArrayDisplay($aArray, "Display ColorMatrix")
EndFunc   ;==>_DisplayColorMatrix

; Parameters:-
;             $Pt1X, $Pt1Y - are the x and y coordinates of point 1
;             $Pt2X, $Pt2Y - are the x and y coordinates of point 2
; Returns: A 2D array:-
;                      $aArray[0] contains the X coordinate of the pixel
;                      $aArray[1] contains the Y coordinate of the pixel
;                      $aArray[3] contains the colour of the pixel in 0xRRGGBB hex. colour format.
;
Func _PixelsInLineToArray($Pt1X, $Pt1Y, $Pt2X, $Pt2Y)
    ConsoleWrite($Pt1X & "  " & $Pt1Y & "  " & $Pt2X & "  " & $Pt2Y & @CRLF)
    If Abs($Pt1X - $Pt2X) > Abs($Pt1Y - $Pt2Y) Then
        If $Pt1X > $Pt2X Then ; If Abs($Pt1X - $Pt2X) has the greater distance, make Point 2 "x" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line
        ; x = x1 +(y - y1)/$m

        Local $aArray[($Pt2X - $Pt1X) + 1][3]
        For $x = $Pt1X To $Pt2X ; Note: $Pt2X has a greater value than $Pt1X.
            $aArray[$x - $Pt1X][0] = $x
            $aArray[$x - $Pt1X][1] = Round(($m * $x) - ($m * $Pt1X) + $Pt1Y, 0)
            $aArray[$x - $Pt1X][2] = "0x" & Hex(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale), 6)
        Next
        Return $aArray
    Else
        If $Pt1Y > $Pt2Y Then ; If Abs($Pt1Y - $Pt2Y) has the greater distance, make Point 2 "y" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line

        Local $aArray[$Pt2Y - $Pt1Y + 1][3]
        For $y = $Pt1Y To $Pt2Y ; Note: $Pt2Y has a greater value than $Pt1Y
            $aArray[$y - $Pt1Y][0] = Round(($y / $m) - ($Pt1Y / $m) + $Pt1X, 0)
            $aArray[$y - $Pt1Y][1] = $y
            $aArray[$y - $Pt1Y][2] = "0x" & Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6)
        Next
        Return $aArray
    EndIf
EndFunc   ;==>_PixelsInLineToArray

 

Edited by Malkey
Updated import image to GUI.

Share this post


Link to post
Share on other sites
On 1/9/2019 at 1:54 PM, Malkey said:

When this example first starts the values in the 5x5 gray-scale color matrix are displayed.

To use this example:- 
Press left mouse button down, drag and move the mouse, then release the left mouse button to draw a line.
Press middle mouse button or Ctrl key to clear lines,
Press Alt+"s" to save the image with the last line drawn. 

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <ScreenCapture.au3>
#include <WinAPIHObj.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <Misc.au3>

Global $scale = _WinAPI_EnumDisplaySettings('', $ENUM_CURRENT_SETTINGS)[0] / @DesktopWidth

Example()

Func Example()
    Local $dll = DllOpen("user32.dll"), $aMPosNew
    If Not FileExists(@ScriptDir & "\cmy-circles.jpg") Then _
            InetGet("http://www.epi-centre.com/basics/color/images/cmy-circles.jpg", _
            @ScriptDir & "\cmy-circles.jpg")

    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\cmy-circles.jpg")
    Local $iWidth = _GDIPlus_ImageGetWidth($hImage)
    Local $iHeight = _GDIPlus_ImageGetHeight($hImage)

    Local $hGUI = GUICreate("GDI+ Example (" & @ScriptName & ")", $iWidth, $iHeight, 10, 10, $WS_POPUP) ;create a test GUI
    GUISetState(@SW_SHOW)

    Local $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI) ;create a graphics object from a window handle
    Local $hBM = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphicGUI) ;create a Bitmap object based on a graphics object
    Local $hGraphicBM = _GDIPlus_ImageGetGraphicsContext($hBM) ;get the graphics context of the image / bitmap to draw on image / bitmap

    _GDIPlus_GraphicsSetSmoothingMode($hGraphicBM, $GDIP_SMOOTHINGMODE_HIGHQUALITY) ;sets the graphics object rendering quality (antialiasing)

    Local $hIA = _GDIPlus_ImageAttributesCreate() ;create an ImageAttribute object
    Local $tColorMatrix = _GDIPlus_ColorMatrixCreateGrayScale() ;create greyscale color matrix
    _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $tColorMatrix) ;set greyscale color matrix

    _GDIPlus_GraphicsClear($hGraphicBM, 0xFF000000)
    _GDIPlus_GraphicsDrawImageRectRect($hGraphicBM, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA) ;draw the bitmap while applying the color adjustment
    _GDIPlus_GraphicsDrawImageRect($hGraphicGUI, $hBM, 0, 0, $iWidth, $iHeight)
    Local $hPen = _GDIPlus_PenCreate(0xffff0000, 2)

    _DisplayColorMatrix($tColorMatrix)

    Do
        Select
            Case _IsPressed("01", $dll) ; Left mouse button down - Drag and move mouse - Release left mouse button to draw a line
                If WinExists("Pixels", "") Then WinClose("Pixels", "")
                $aMPos = MouseGetPos()
                Do
                    Sleep(10)
                Until Not _IsPressed("01", $dll)
                $aMPosNew = MouseGetPos()
                Local $aArr = _PixelsInLineToArray($aMPos[0], $aMPos[1], $aMPosNew[0], $aMPosNew[1])
                If UBound($aArr) > 1 Then
                    _GDIPlus_GraphicsDrawLine($hGraphicGUI, $aMPosNew[0], $aMPosNew[1], $aMPos[0], $aMPos[1], $hPen)
                    _ArrayDisplay($aArr, "Pixels")
                EndIf
            Case _IsPressed("04", $dll) Or _IsPressed("11", $dll) ; Press middle mouse button, or, Ctrl key to clear lines
                _GDIPlus_GraphicsClear($hGraphicBM)
                _GDIPlus_GraphicsClear($hGraphicGUI)
                _GDIPlus_GraphicsDrawImageRectRect($hGraphicBM, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA) ;draw the bitmap while applying the color adjustment
                _GDIPlus_GraphicsDrawImageRect($hGraphicGUI, $hBM, 0, 0, $iWidth, $iHeight)
            Case _IsPressed("12", $dll) And _IsPressed("53", $dll) ; Press Alt + "s" to save image
                _GDIPlus_GraphicsDrawLine($hGraphicBM, $aMPosNew[0], $aMPosNew[1], $aMPos[0], $aMPos[1], $hPen)
                _GDIPlus_ImageSaveToFile($hBM, @ScriptDir & "\SCTesta.jpg")
                ShellExecuteWait(@ScriptDir & "\SCTesta.jpg")

        EndSelect
    Until GUIGetMsg() = $GUI_EVENT_CLOSE

    ;cleanup GDI+ resources
    _GDIPlus_ImageAttributesDispose($hIA)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _GDIPlus_GraphicsDispose($hGraphicBM)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_BitmapDispose($hBM)
    _GDIPlus_Shutdown()
    GUIDelete($hGUI)
EndFunc   ;==>Example

Func _DisplayColorMatrix($tCMStruct) ; See $tagGDIPCOLORMATRIX AutoIt Help File
    Local $aArray[5][5]
    For $i = 1 To 5
        For $j = 1 To 5
            $aArray[$i - 1][$j - 1] = DllStructGetData($tCMStruct, 1, (($i - 1) * 5) + $j)
        Next
    Next
    _ArrayDisplay($aArray, "Display ColorMatrix")
EndFunc   ;==>_DisplayColorMatrix

; Parameters:-
;             $Pt1X, $Pt1Y - are the x and y coordinates of point 1
;             $Pt2X, $Pt2Y - are the x and y coordinates of point 2
; Returns: A 2D array:-
;                      $aArray[0] contains the X coordinate of the pixel
;                      $aArray[1] contains the Y coordinate of the pixel
;                      $aArray[3] contains the colour of the pixel in 0xRRGGBB hex. colour format.
;
Func _PixelsInLineToArray($Pt1X, $Pt1Y, $Pt2X, $Pt2Y)
    ConsoleWrite($Pt1X & "  " & $Pt1Y & "  " & $Pt2X & "  " & $Pt2Y & @CRLF)
    If Abs($Pt1X - $Pt2X) > Abs($Pt1Y - $Pt2Y) Then
        If $Pt1X > $Pt2X Then ; If Abs($Pt1X - $Pt2X) has the greater distance, make Point 2 "x" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line
        ; x = x1 +(y - y1)/$m

        Local $aArray[($Pt2X - $Pt1X) + 1][3]
        For $x = $Pt1X To $Pt2X ; Note: $Pt2X has a greater value than $Pt1X.
            $aArray[$x - $Pt1X][0] = $x
            $aArray[$x - $Pt1X][1] = Round(($m * $x) - ($m * $Pt1X) + $Pt1Y, 0)
            $aArray[$x - $Pt1X][2] = "0x" & Hex(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale), 6)
        Next
        Return $aArray
    Else
        If $Pt1Y > $Pt2Y Then ; If Abs($Pt1Y - $Pt2Y) has the greater distance, make Point 2 "y" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line

        Local $aArray[$Pt2Y - $Pt1Y + 1][3]
        For $y = $Pt1Y To $Pt2Y ; Note: $Pt2Y has a greater value than $Pt1Y
            $aArray[$y - $Pt1Y][0] = Round(($y / $m) - ($Pt1Y / $m) + $Pt1X, 0)
            $aArray[$y - $Pt1Y][1] = $y
            $aArray[$y - $Pt1Y][2] = "0x" & Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6)
        Next
        Return $aArray
    EndIf
EndFunc   ;==>_PixelsInLineToArray

 

2

Malkey,

once again: thank you very much for your help.

I always wonder how you guys manage to post entire scripts as replies: takes me many days to get my stuff working, and you seem to be able to write withing 10min... :o

I am currently stuck and working on another problem, but will soon implement your solution. 

Best regards,

dejhost

Share this post


Link to post
Share on other sites

Do you know the (old) Star-Wars scene where a X-wing tries to defeat the death-star? Trying to get into the right position to fire the torpedo, the pilot repeats "I'm almost there...I'm almost there...". I just feel the same way ;-)   Hopefully in the end more lucky than the X-wing pilot, though...

A remaining problem I have: The two functions "PixelGetColor()" and "_GDIPlus_GraphicsDrawLine()" (used to save the image together with the line) seem to use a different Coordinate system than the rest of my program. I placed

Opt("PixelCoordMode", 0) ;1=absolute, 0=relative, 2=client

in the beginning of the subroutines, and tried all three options. None of the options results in correct output. The colors extracted show different values than expected, and the image saved shows the line that was drawn by the user at the wrong position.

I believe it has something to do with the image position and the image dimension that I handle wrong(?) Here is the relevant code. It's not the complete code (which is too untidy to be published :'( . Yes. Far more untidy than the code below...).

Global $scale = _WinAPI_EnumDisplaySettings('', $ENUM_CURRENT_SETTINGS)[0] / @DesktopWidth
Global $hUserDll = DllOpen("user32.dll")
Global $hGraphics, $hGraphicBM, $pos, $iWidth, $iHeight, $hBM, $hIA
Global $scale = 1;_WinAPI_EnumDisplaySettings('', $ENUM_CURRENT_SETTINGS)[0] / @DesktopWidth
Global $aArray

Opt("MustDeclareVars", 1)
Opt("MouseCoordMode", 1)
Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase


Func _LoadImage()
;Load Image
    $sFile = FileOpenDialog("Select an image", "", "Images (*.bmp;*.png;*.jpg;*.gif;*.tif)", 1)
    $Path =_Pathsplit($sFile, $sDrive, $sDir, $sFileName, $sExtension)
        If @error Or Not FileExists($sFile) Then MsgBox($MB_SYSTEMMODAL, "File doesn't exist - 267", "Error opening file " & $Path)
    $hImage = _GDIPlus_ImageLoadFromFile($sFile)
    _WinAPI_DeleteObject($hImage) ;release GDI bitmap resource because not needed anymore
    $iWidth = _GDIPlus_ImageGetWidth($hImage)
    $iHeight = _GDIPlus_ImageGetHeight($hImage)

;== DRAW IMAGE, APPLYING GRAYSCALE IF NECESSARY
; GUI
;~  Global $iWidth = @DesktopWidth*3/4;
;~  Global $iHeight = @DesktopHeight*3/4;_GDIPlus_ImageGetHeight($hImage) * $iWidth / _GDIPlus_ImageGetWidth($hImage)
    Global $hGui2 = GUICreate("GDI+ v1.1 (" & @ScriptName & ")", $iWidth, $iHeight)
    GUISetState(@SW_SHOW)

;GREYSCALE
     $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI2) ;create a graphics object from a window handle
     $hBM = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphics)
        $hGraphicBM = _GDIPlus_ImageGetGraphicsContext($hBM)
         $hIA = _GDIPlus_ImageAttributesCreate() ;create an ImageAttribute object
    Global $tColorMatrix = _GDIPlus_ColorMatrixCreateGrayScale() ;create greyscale color matrix
    _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $tColorMatrix) ;set greyscale color matrix
    WinClose(StringRegExpReplace($sFile, "^.*\\|\..*$", ""))
    If NOT _IsImageGrayScale($sFile) Then
        _GDIPlus_GraphicsDrawImageRectRect($hGraphics, $hImage, 0, 0, _GDIPlus_ImageGetWidth($hImage), _GDIPlus_ImageGetHeight($hImage), 0, 0, $iWidth, $iHeight,$hiA);, 0, 0, 1400, 900,$hIA ) ;draw the bitmap while applying the color adjustment
    Else
        _GDIPlus_GraphicsDrawImageRectRect($hGraphics, $hImage, 0, 0, _GDIPlus_ImageGetWidth($hImage), _GDIPlus_ImageGetHeight($hImage), 0, 0, $iWidth, $iHeight);, 0, 0, 1400, 900,$hIA ) ;draw the bitmap while applying the color adjustment
    EndIf

Return $Path
EndFunc   ;==>LoadImage


Func _SaveScreenshot()
;~  $iWidth = _GDIPlus_ImageGetWidth($hImage)
;~  $iHeight = _GDIPlus_ImageGetHeight($hImage)
;~  Local $hGUI = GUICreate("GDI+ Example (" & @ScriptName & ")", $iWidth, $iHeight, 10, 10, $WS_POPUP) ;create a test GUI

    Local $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI2) ;create a graphics object from a window handle
    Local $hBM = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphicGUI) ;create a Bitmap object based on a graphics object
    Local $hGraphicBM = _GDIPlus_ImageGetGraphicsContext($hBM) ;get the graphics context of the image / bitmap to draw on image / bitmap

    _GDIPlus_GraphicsClear($hGraphicBM, 0xFF000000)
    _GDIPlus_GraphicsDrawImageRectRect($hGraphicBM, $hImage, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA) ;draw the bitmap while applying the color adjustment
    _GDIPlus_GraphicsDrawImageRect($hGraphicGUI, $hBM, 0, 0, $iWidth, $iHeight)
    Local $hPen = _GDIPlus_PenCreate(0xffff0000, 2)

    _GDIPlus_GraphicsDrawLine($hGraphicBM, $Pt1[0], $Pt1[1], $Pt2[0], $Pt2[1], $hPen)
    _GDIPlus_ImageSaveToFile($hBM, @ScriptDir & "\screenshot.jpg")
;~     ShellExecuteWait(@ScriptDir & "\screenshot.jpg")Sc
EndFunc ;==>_SaveScreenshot


Func _PixelsInLineToArray($Pt1X, $Pt1Y, $Pt2X, $Pt2Y)
   Local $m

    ProgressOn("Progress of Pixel processing", "", "0%", 100, 100) ; Display progressbar

    If Abs($Pt1X - $Pt2X) > Abs($Pt1Y - $Pt2Y) Then
        If $Pt1X > $Pt2X Then ; If Abs($Pt1X - $Pt2X) has the greater distance, make Point 2 "x" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient
        ; y - y1 = $m(x - x1) ; Equation for a straight line

        Global $aArray[($Pt2X - $Pt1X) + 1][3]
        For $x = $Pt1X To $Pt2X ; Note: $Pt2X has a greater value than $Pt1X.
            ;msgbox(0,"progress value",Floor($x / $Pt2X * 100) & "%",1)

            $aArray[$x - $Pt1X][0] = $x
            $aArray[$x - $Pt1X][1] = Round(($m * $x) - ($m * $Pt1X) + $Pt1Y, 0) ; y = $m(x - x1) + y1  (y value from equation for a straight line)
            $aArray[$x - $Pt1X][2] = Dec(StringRight(Hex(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale), 6), 2))
            ;$aArray[$x - $Pt1X][2] = "0x" & Hex(PixelGetColor($aArray[$x - $Pt1X][0] * $scale, $aArray[$x - $Pt1X][1] * $scale), 6)
            ProgressSet(Floor($x / $Pt2X * 100),"%","soon finished calculating") ;increase Progressbar
        Next
        ProgressSet(100, "Done", "operation completed")
        Sleep(1000)
        ProgressOff()
        ;_ArrayDisplay($aArray)
        Return $aArray
    Else
        If $Pt1Y > $Pt2Y Then ; If Abs($Pt1Y - $Pt2Y) has the greater distance, make Point 2 "y" value have the larger value.
            Local $TempX, $TempY
            $TempX = $Pt1X
            $TempY = $Pt1Y
            $Pt1X = $Pt2X
            $Pt1Y = $Pt2Y
            $Pt2X = $TempX
            $Pt2Y = $TempY
        EndIf
        $m = ($Pt2Y - $Pt1Y) / ($Pt2X - $Pt1X) ; line's gradient

        Global $aArray[$Pt2Y - $Pt1Y + 1][3]
        For $y = $Pt1Y To $Pt2Y ; Note: $Pt2Y has a greater value than $Pt1Y
            ;msgbox(0,"progress value",Floor($y / $Pt2y * 100)& "%",1)
            $aArray[$y - $Pt1Y][0] = Round(($y / $m) - ($Pt1Y / $m) + $Pt1X, 0) ; x = (y - y1)/$m + x1 (x value from equation for a straight line)
            $aArray[$y - $Pt1Y][1] = $y
            $aArray[$y - $Pt1Y][2] = Dec(StringRight(Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6), 2))
            ;$aArray[$y - $Pt1Y][2] = "0x" & Hex(PixelGetColor($aArray[$y - $Pt1Y][0] * $scale, $aArray[$y - $Pt1Y][1] * $scale), 6)
            ProgressSet(Floor($y / $Pt2Y *100),"%","soon finished calculating")

        Next
        ProgressSet(100, "Done", "operation completed")
        Sleep(1000)
        ProgressOff()
        ;_ArrayDisplay($aArray)
        Return $aArray
    EndIf
EndFunc   ;==>_PixelsInLineToArray

I cannot get my head around this, because I do not yet understand the code in all details yet. Could somebody please help me out?

Edited by dejhost
Improved explanations

Share this post


Link to post
Share on other sites
2 hours ago, Nine said:

use _GDIPlus_BitmapGetPixel instead

I implemented the _GDIPlus_BitmapGetPixel into _PixelsInLineToArray. It appears that the _PixelsInLineToArray has now the same coordinate system as _SaveScreenshot. So definatevly an improvement.

Now I need to get both consistent with what the user sees/draws. 

Share this post


Link to post
Share on other sites

Here another way to do it. I draw a bezier curve and read out the colors of that curve. You can us a line instead. Advantage is that you do not need to calculate the path of any line to read out the pixel color accordingly.

#include <ScreenCapture.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

_GDIPlus_Startup()

Global Const $hGUI = GUICreate("Test", 512, 512)
GUISetState()

Global Const $hHBitmap = _ScreenCapture_Capture("", 0, 0, 511, 511, False), _
             $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap), _
             $hGfx = _GDIPlus_ImageGetGraphicsContext($hImage), _
             $hImage2 = _GDIPlus_BitmapCreateFromScan0(512, 512), _
             $hGfx2 = _GDIPlus_ImageGetGraphicsContext($hImage2), _
             $hPen = _GDIPlus_PenCreate(0xFFFF0000, 8) ;change the pen size accordingly

_GDIPlus_GraphicsSetSmoothingMode($hGfx2, 0)
_GDIPlus_GraphicsDrawBezier($hGfx2, 50,  50, _
                                   100, 350, _
                                   325,  25, _
                                   450, 500, $hPen)

Global Const $hCanvas = _GDIPlus_GraphicsCreateFromHWND($hGUI)
_GDIPlus_GraphicsDrawImageRect($hCanvas, $hImage, 0, 0, 511, 511)
_GDIPlus_GraphicsDrawImageRect($hCanvas, $hImage2, 0, 0, 511, 511)
Global $aColors = GetColors($hImage2, $hImage), $i
Global $hImageResult = _GDIPlus_BitmapCreateFromScan0(512, 512, $GDIP_PXF24RGB)
For $i = 0 To UBound($aColors) - 1
    _GDIPlus_BitmapSetPixel($hImageResult, $aColors[$i][0], $aColors[$i][1], $aColors[$i][2]) ;slow - faster is to use _GDIPlus_BitmapLockBits() but I was to lazy :-)
Next
MsgBox(0, "Test", "Click OK to view result")

_GDIPlus_GraphicsDrawImageRect($hCanvas, $hImageResult, 0, 0, 511, 511)

;_ArrayDisplay($aColors)

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

_WinAPI_DeleteObject($hHBitmap)
_GDIPlus_PenDispose($hPen)
_GDIPlus_GraphicsDispose($hGfx)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hGfx2)
_GDIPlus_ImageDispose($hImage2)
_GDIPlus_ImageDispose($hImageResult)
_GDIPlus_Shutdown()

Func GetColors($hBitmap1, $hBitmap2, $iSearchColor = 0xFFFF0000)
    Local $aDim = _GDIPlus_ImageGetDimension($hBitmap1)
    Local $iW = $aDim[0], $iH = $aDim[1]
    ;this is the bitmap with the red bezier only
    Local $tBitmapData1 = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB) ;locks a portion of a bitmap for reading and writing. More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx
    Local $iScan01 = DllStructGetData($tBitmapData1, "Scan0") ;get scan0 (pixel data) from locked bitmap
    Local $tPixel1 = DllStructCreate("int[" & $iW * $iH & "];", $iScan01)

    ;this is the bitmap where we read the colors
    Local $tBitmapData2 = _GDIPlus_BitmapLockBits($hBitmap2, 0, 0, $iW, $iH, $GDIP_ILMREAD, $GDIP_PXF32ARGB) ;locks a portion of a bitmap for reading and writing. More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx
    Local $iScan02 = DllStructGetData($tBitmapData2, "Scan0") ;get scan0 (pixel data) from locked bitmap
    Local $tPixel2 = DllStructCreate("int[" & $iW * $iH & "];", $iScan02)

    Local $iPixel, $iRowOffset, $p = 0
    Local $aColors[$iW * $iH][3] ;x, y, color
    For $iY = 0 To $iH - 1
        $iRowOffset = $iY * $iW + 1
        For $iX = 0 To $iW - 1 ;get each pixel in each line and row
            $iPixel = DllStructGetData($tPixel1, 1, $iRowOffset + $iX) ;get pixel color from bezier
            If $iPixel = $iSearchColor Then
                $aColors[$p][0] = $iX
                $aColors[$p][1] = $iY
                $aColors[$p][2] = DllStructGetData($tPixel2, 1, $iRowOffset + $iX) ;save pixel color from original image without bezier
                $p += 1
            EndIf
        Next
    Next
    _GDIPlus_BitmapUnlockBits($hBitmap1, $tBitmapData1) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits
    _GDIPlus_BitmapUnlockBits($hBitmap2, $tBitmapData2) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits
    ReDim $aColors[$p - 1][3]
    Return $aColors
EndFunc

 

I don't know whether this is something your are looking for...


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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
;Call the function:
_PixelsInLineToArray($Pt1[0]-$centerX, $Pt1[1]-$centerY, $Pt2[0]-$centerX, $Pt2[1]-$centerY)

@UEZ: Thank you very much. But since I was "almost there..." anyhow, I decided to bring the first approach to its well-deserved glory, first. I have of course looked at your code, but I need more time to study the "GetColors" function more closely. Will do so soon and compare both approaches.

Finally managed to fix the coordinate problem for both: saving the image and the pixel2array: Also Malkey's code saves a faulty line. Reason is that the image has a "left =10" and "top = 10" position when it get drawn. So the line that is saved is actually 10 pixels too far to the right, and 10 pixels too far down.

Im my code, the image is drawn centered. That means that both functions (getColors and pixel2array) need to get corrected accordingly:
 

$centerX = (@DesktopWidth/2)-($iWidth/2)
$centerY = (@DesktopHeight/2)-($iHeight/2)

Call of the function Pixel2Array:

_PixelsInLineToArray($Pt1[0]-$centerX, $Pt1[1]-$centerY, $Pt2[0]-$centerX, $Pt2[1]-$centerY)
$aArray[$x - $Pt1X][0] = $centerX + $x
$aArray[$x - $Pt1X][1] = $centery + Round(($m * $x) - ($m * $Pt1X) + $Pt1Y, 0) ; y = $m(x - x1) + y1  (y value from equation for a straight line)
$aArray[$x - $Pt1X][2] = Dec(StringRight(Hex(PixelGetColor(($aArray[$x - $Pt1X][0] * $scale), ($aArray[$x - $Pt1X][1] * $scale)), 6), 2))

In the function SaveImage:

_GDIPlus_GraphicsDrawLine($hGraphicBM, $Pt1[0]-$centerX, $Pt1[1]-$centerY, $Pt2[0]-$centerX, $Pt2[1]-$centerY,$hPen)

 

 

 

 

 

Edited by dejhost
more context

Share this post


Link to post
Share on other sites

Last question - just out of curiosity: would it be possible to extract the pixelcolor from a closed image?

My reason for asking: if the image has to be opened, then it might have to be resized in order to fit the screen. Only then the user can see the entire image, and indicate start- and endpoint of the line. But in this means that the extracted grayvalues do not refer to the original image - only to the resized one. Information gets lost.

Share this post


Link to post
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

  • Similar Content

    • By Rskm
      Hi, I am using excel as input media for my program. The excel file (i tried with .xls, .xlsx and .xlsm format) has inputs which the autoit script reads during the run and performs few calculations. Some times (not always), after the run, when i try to open the excel file manually, the file doesnt open at all in excel. see the screenshot attached. However, if the execute the autoit script, the scripts still reads the existing data from that excel and performs the calcs. I copied the excel file to another computer and there too, it doesnt open.  So, after this, i cannot edit the excel forever (if i need to change any inputs). It is only this particular file that got affected. other excel files works normal.  What could be the problem here.  please help as this is a new challenge for me during my program development. 

    • By argumentum
      ..I'm coding the High Contrast theme editor and using the _ChooseColor() I wandered why it does not keep the the custom colors I've added.
      Found that adding a static declaration would do it. But why stop there. Why not keep going, So I put this together that is non code braking ( backwards compatible ), to replace the one in <Misc.au3>
      _ChooseColor_mod_Example() Func _ChooseColor_mod_Example() Local $aCustColors[17] $aCustColors[1] = 0xFF0000 $aCustColors[16] = 0x0000FF $aCustColors = _ChooseColor_mod(2, "0x00ff00", 2, 0, $aCustColors) ConsoleWrite(@CRLF & $aCustColors[0] & @CRLF & @CRLF) ConsoleWrite(@CRLF & _ChooseColor_mod(2, $aCustColors[0], 2, 0, $aCustColors)[0] & @CRLF & @CRLF) ConsoleWrite(@CRLF & _ChooseColor_mod(2, "0x00ff00", 2) & @CRLF & @CRLF) ; just as default behaviour ConsoleWrite(@CRLF & _ChooseColor_mod(2, "0x00ff00", 2, 0, 'reset as is neither "Default" nor "Array[17]"') & @CRLF & @CRLF) ; just as default behaviour EndFunc ;==>_ChooseColor_mod_Example ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ChooseColor_mod ; Description ...: ; Syntax ........: _ChooseColor_mod([$iReturnType = 0[, $iColorRef = 0[, $iRefType = 0[, $hWndOwnder = 0[, $vCustColors = Default]]]]]) ; Parameters ....: $iReturnType - [optional] an integer value. Default is 0. See remarks for values. ; $iColorRef - [optional] an integer value. Default is 0. ; $iRefType - [optional] an integer value. Default is 0. See remarks for values. ; $hWndOwnder - [optional] a handle to the parent window. Default is 0. ; $vCustColors - [optional] an array of colors to show as custom values. See remarks for values. ; Return values .: Success - Hex value of the selected color ; Failure - $vCustomColors is returned if set, otherwise, -1 is returned. Also sets @error: ; | -2 - User initialized $tagCustcolors via $vCustColors. ; | -3 - User canceled or invalid dll struct. ; | -4 - Invalid $iReturnType value. ; | Other - Error returned from Dll call. ; Author ........: Gary Frost (gafrost) ; Modified ......: argumentum ; Remarks .......: $iReturnType can be 0 (RGB COLORREF), 1 (Hex BGR), or 2 (Hex RGB). ; $iRefType can be 0 (ColorRef), 1 (BGR Hex), or 2 (RGB Hex). ; $vCustColors is a zero based array[17] where: ; index 0 hold the color returned by the function. ; index 1 to 16 are the colors to use in Custom colors in RGB. ; One can pass the array with array[0] = -2 to initialize the custom colors without loading the interface. ; When $vCustColors is used, it returns the modified array. ( not the color as integer ). ; Anything other than Default or a proper array, will clear $tagCustcolors ( holder of the custom colors ). ; When $vCustColors is omited or Default, $tagCustcolors is kept ( hence, no need for the array to keep custom colors ). ; Related .......: Same Func from <Misc.au3> ; Link ..........: https://www.autoitscript.com/forum/topic/200985-_choosecolor-but-better/ ; Example .......: YES ; =============================================================================================================================== Func _ChooseColor_mod($iReturnType = 0, $iColorRef = 0, $iRefType = 0, $hWndOwnder = 0, $vCustColors = Default) ; basic code from Misc.au3 ; https://www.autoitscript.com/forum/topic/200985-_choosecolor-but-better/ ; added here for independance of #include <Misc.au3> Local Static $tagCHOOSECOLOR = "dword Size;hwnd hWndOwnder;handle hInstance;dword rgbResult;ptr CustColors;dword Flags;lparam lCustData;" & _ "ptr lpfnHook;ptr lpTemplateName" Local Static $__MISCCONSTANT_CC_ANYCOLOR = 0x0100 Local Static $__MISCCONSTANT_CC_FULLOPEN = 0x0002 Local Static $__MISCCONSTANT_CC_RGBINIT = 0x0001 ; added here for independance of #include <Misc.au3> Local $vReturn, $bCustColors = False, $tagCustcolors = "dword[16]" Local $tChoose = DllStructCreate($tagCHOOSECOLOR) Local Static $tCc = DllStructCreate($tagCustcolors) ; added Static (mod.), to keep $tagCustcolors changes by user when called again. If $vCustColors == Default Then ; nothing ElseIf UBound($vCustColors) = 17 Then $bCustColors = True For $n = 1 To 16 DllStructSetData($tCc, 1, $vCustColors[$n], $n) Next Else $tCc = DllStructCreate($tagCustcolors) ; reset, just in case you'd want to have it default again EndIf If $iRefType = 1 Then ; BGR hex color to colorref $iColorRef = Int($iColorRef) ElseIf $iRefType = 2 Then ; RGB hex color to colorref $iColorRef = Hex(String($iColorRef), 6) $iColorRef = '0x' & StringMid($iColorRef, 5, 2) & StringMid($iColorRef, 3, 2) & StringMid($iColorRef, 1, 2) EndIf DllStructSetData($tChoose, "Size", DllStructGetSize($tChoose)) DllStructSetData($tChoose, "hWndOwnder", $hWndOwnder) DllStructSetData($tChoose, "rgbResult", $iColorRef) DllStructSetData($tChoose, "CustColors", DllStructGetPtr($tCc)) DllStructSetData($tChoose, "Flags", BitOR($__MISCCONSTANT_CC_ANYCOLOR, $__MISCCONSTANT_CC_FULLOPEN, $__MISCCONSTANT_CC_RGBINIT)) Local $aResult = DllCall("comdlg32.dll", "bool", "ChooseColor", "struct*", $tChoose) If @error Then If Not $bCustColors Then Return SetError(@error, @extended, -1) Else $vCustColors[0] = -1 Return SetError(@error, @extended, $vCustColors) EndIf EndIf If $bCustColors Then ; this here is better than at the end, For $n = 1 To 16 ; that way you'll get the custom colors anyway. $vCustColors[$n] = DllStructGetData($tCc, 1, $n) Next If $vCustColors[0] = -2 Then Return $vCustColors EndIf If $aResult[0] = 0 Then ; Return SetError(-3, -3, -1) ; user selected cancel or struct settings incorrect If Not $bCustColors Then Return SetError(-3, -3, -1) Else $vCustColors[0] = -1 Return SetError(-3, -3, $vCustColors) EndIf EndIf Local $sColor_picked = DllStructGetData($tChoose, "rgbResult") If $iReturnType = 1 Then ; return Hex BGR Color $vReturn = '0x' & Hex(String($sColor_picked), 6) ElseIf $iReturnType = 2 Then ; return Hex RGB Color $sColor_picked = Hex(String($sColor_picked), 6) $vReturn = '0x' & StringMid($sColor_picked, 5, 2) & StringMid($sColor_picked, 3, 2) & StringMid($sColor_picked, 1, 2) ElseIf $iReturnType = 0 Then ; return RGB COLORREF $vReturn = $sColor_picked Else $vReturn = -1 SetError(-4, -4) EndIf If Not $bCustColors Then Return $vReturn $vCustColors[0] = $vReturn Return $vCustColors EndFunc ;==>_ChooseColor_mod Hopefully will replace the default one in the next release 
    • By Taxyo
      Hi,
       
      I've been trying to automate modification of an excel file and the last thing I am stuck on is deleting all the rows where the value of Column 13 is 0. 
      I believe the error is due to me not fully understanding the syntax so this is where I'm stuck: 
       
      Func Hotkey2() Global $aUsedRange = _Excel_RangeRead($oWorkbook, 1) _ArrayDisplay($aUsedRange) For $iRow = UBound($aUsedRange) - 1 to 3 Step -1 If $aUsedRange[$iRow][13] = 0 Then _Excel_RangeDelete($oWorkbook.Worksheets(1), $aUsedRange[$iRow] & ":" & $aUsedRange[$iRow], default, 1) If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeDelete Example 2", "Error deleting rows." & @CRLF & "@error = " & @error & ", @extended = " & @extended) EndIf Next EndFunc  
      While my script properly locates the row which contains value 0 in Column 13, I am not sure how to set it to the corresponding row in the excel workbook?  My above experiment gives me $vRange error and I've been toying around with it to no avail. The only way I get the Script to delete a row is by actually specifying "4:4" or "6:8" etc. 
      Where am I going wrong?
       
      Thanks! 
    • By Most
      #include <Array.au3> #include <Excel.au3> #include <MsgBoxConstants.au3> ; Create application object and open an example workbook Local $oExcel = _Excel_Open() If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeRead Example", "Error creating the Excel application object." & @CRLF & "@error = " & @error & ", @extended = " & @extended) Local $oWorkbook = _Excel_BookOpen($oExcel, @ScriptDir & "\trans.xlsx") If @error Then MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeRead Example", "Error opening workbook '" & @ScriptDir & "\trans.xlsx'." & @CRLF & "@error = " & @error & ", @extended = " & @extended) _Excel_Close($oExcel) Exit EndIf ; ***************************************************************************** ; Read data from a single cell on the active sheet of the specified workbook ; ***************************************************************************** Local $sResult = _Excel_RangeRead($oWorkbook, Default, "A1") If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeRead Example 1", "Error reading from workbook." & @CRLF & "@error = " & @error & ", @extended = " & @extended) MsgBox($MB_SYSTEMMODAL, "Excel UDF: _Excel_RangeRead Example 1", "Data successfully read." & @CRLF & "Value of cell A1: " & $sResult) Hi, all.
      Ok, here is the deal. I have simple excel file called trans.xlsx. It's located in the directory of script. In general i don't care where to store it. 
      What i do need is to open excel file and copy one by one numbers from cells. I've tried different ways, examples. But i only get error, says: error = 3, extended = 1. I saw different posts from different years. I even tried to use simple example from manual file. But always get error.

      In general my goal get numbers one by one and post it to let's say search filed in my PC one by one. Or to notepad (but one by one, in kind of loop). 
      I've learned how to copy or show in message box some info from other apps. But with excel i'm stuck. 

      I'm able to open needed window based on "title" of excel. But i don't succeed of copying info from cells. 

      Would be appreciate for any help. 
      So, in this code i'm trying at least to read from cell A1. Doesn't matter what Sheet. 

      I use Windows 10, Excel for Office 365. 
      Thank you in advance. 
×
×
  • Create New...