OpenCV meets AutoIt

  • @AJ: Danke ich werde mir das mal reinziehen.

    Andy: Ich hab den Fehler gefunden. Anscheinend will er die Positionen doch nicht als Struct haben, sondern direkt als Int-Werte. Aber laut der cpp-Datei will er es aber als Struct haben. Das verwirrt mich ein bisschen. Naja egal. So muss es dann aussehen:

    Spoiler anzeigen
    [autoit]

    Func _OpenCV_Circle($_tImage, $_iX, $_iY, $_iRadius, $_iColor = 0xFFFFFF, $_iThickness = 1, $_iLineType = 8, $_iShift = 0)
    Local $_iR = BitAND(BitShift($_iColor, 16), 0xFF)
    Local $_iG = BitAND(BitShift($_iColor, 8), 0xFF)
    Local $_iB = BitAND($_iColor, 0xFF)
    DllCall($__ghOCVDll_1, "none:cdecl", "cvCircle", "ptr", DllStructGetPtr($_tImage), "int", $_iX, "int", $_iY, "int", $_iRadius, _
    "double", $_iB, "double", $_iG, "double", $_iR, "double", 0, "int", $_iThickness, "int", $_iLineType, "int", $_iShift)
    If @error Then Return SetError(@error, 0, 0)
    Return 1
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _OpenCV_Ellipse($_tImage, $_iX, $_iY, $_iWidth, $_iHeight, $_iAngle, $_iStartAngle, $_iEndAngle, $_iColor = 0xFFFFFF, $_iThickness = 1, $_iLineType = 1, $_iShift = 0)
    Local $_iR = BitAND(BitShift($_iColor, 16), 0xFF)
    Local $_iG = BitAND(BitShift($_iColor, 8), 0xFF)
    Local $_iB = BitAND($_iColor, 0xFF)
    DllCall($__ghOCVDll_1, "none:cdecl", "cvEllipse", "ptr", DllStructGetPtr($_tImage), "int", $_iX, "int", $_iY, "int", $_iWidth, "int", $_iHeight, _
    "double", $_iAngle, "double", $_iStartAngle, "double", $_iEndAngle, _
    "double", $_iB, "double", $_iG, "double", $_iR, "double", 0, "int", $_iThickness, "int", $_iLineType, "int", $_iShift)
    If @error Then Return SetError(@error, 0, 0)
    Return 1
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _OpenCV_Line($_tImage, $_iX1, $_iY1, $_iX2, $_iY2, $_iColor = 0xFFFFFF, $_iThickness = 1, $_iLineType = 8, $_iShift = 0)
    Local $_iR = BitAND(BitShift($_iColor, 16), 0xFF)
    Local $_iG = BitAND(BitShift($_iColor, 8), 0xFF)
    Local $_iB = BitAND($_iColor, 0xFF)
    DllCall($__ghOCVDll_1, "none:cdecl", "cvLine", "ptr", DllStructGetPtr($_tImage), "int", $_iX1, "int", $_iY1, "int", $_iX2, "int", $_iY2, _
    "double", $_iB, "double", $_iG, "double", $_iR, "double", 0, "int", $_iThickness, "int", $_iLineType, "int", $_iShift)
    If @error Then Return SetError(@error, 0, 0)
    Return 1
    EndFunc

    [/autoit]


    Aber wie immer...Hauptsache es funktioniert.

  • Dank progandy hab ich auch das jetzt mit dem Struct als Rückgabetyp geschafft. Einfach das Struct als Referenz übergeben, also als Pointer. Aber als erster Parameter.
    So:

    [autoit]

    Func _OpenCV_GetImageROI($_tImage)
    Local $tRect = DllStructCreate($tagCvRect)
    DllCall($__ghOCVDll_1, "none:cdecl", "cvGetImageROI", "ptr", DllStructGetPtr($tRect), "ptr", DllStructGetPtr($_tImage))
    If @error Then Return SetError(@error, 0, 0)
    Return $tRect
    EndFunc

    [/autoit]
  • Und für das Zeug mit den Strukturen als Parmetern, verwende den Typ "struct" ohne Stern. Und dann die Struct direkt als Parameter. Wenn gerade kein Bug auftritt, dann sollte das funktionieren.

    [autoit]

    $tStruct = DLLStructCreate()
    DLLCall($dll, "int", "function", "struct", $tStruct)

    [/autoit]
  • Ne das klappt nicht. Ich muss echt die Int-Werte direkt hinschreiben.

    Gibts eigentlich einen Unterschied zwischen

    [autoit]

    "ptr", DllStructGetPtr($_tImage)

    [/autoit]


    und

    [autoit]

    "struct*", $_tImage

    [/autoit]


    ?

  • Gibts eigentlich einen Unterschied zwischen


    Nicht wirklich. struct* erkennt automatisch, ob es einen Pointer oder eine DLLStruct bekommen hat und wandelt diese dann automatisch in den Pointer um. Es erspart dir also Logik wenn die Funktion sowohl mit Pointern als auch DLLStructs als Paramter funktionieren soll. struct ohne Stern sollte das gleiche Ergebnis liefern wie das Auflisten der Elemente als Parameter (solange man mit 32bit und 64bit Werten und nicht einzelnen Bytes arbeitet) , aber da hat die aktuelle Version eventuell noch ein oder zwei Bugs.

  • Danke progandy.

    So das nächste:

    Code
    selection &= Rect(0, 0, image.cols, image.rows);


    selection ist eine Struktur mit dem selben Aufbau wie Rect.
    Muss ich das mit BitAND umsetzen oder die jeweiligen Elemente addieren?

  • Bist du sicher das es sich bei Selection um eine Struktur (also dann wahrscheinlich cvRect) handelt und nicht um das C++-Objekt cv::Rect_?
    Weil dafür existiert eine Operatorüberladung für den &=-Operator.
    Da müsstest du eigentlich in der Definition von cv::Rect nachschauen wie das dort implementiert ist.
    Ich habe allerdings kurz im Source nachgeschaut und auf die Schnelle nicht wirklich was brauchbares gefunden.

  • Es ist ein Rect, hier das gesamte Beispiel:

    Spoiler anzeigen
  • Also doch keine Struktur sondern ein Objekt.
    Die Operator-Überladung hierfür findet sich in der operations.hpp:

    Definition Operator
    Code
    template<typename _Tp> static inline Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
    {
        _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y);
        a.width = std::min(a.x + a.width, b.x + b.width) - x1;
        a.height = std::min(a.y + a.height, b.y + b.height) - y1;
        a.x = x1; a.y = y1;
        if( a.width <= 0 || a.height <= 0 )
            a = Rect();
        return a;
    }


    Spontan sehe ich von AutoIt aus nicht viele Möglichkeiten außer dies selbst zu implementieren da ich nicht wüsste wie man darauf von AutoIt per C-Schnittstelle zugreifen kann.

  • Naja, so wie das für mich aussieht, werden doch einfach nur die beiden RECT miteinander verknüpft, wobei RECT_b eine Konstante ist

    also einfaches Umsetzen von AspirinJunkies Code

    Spoiler anzeigen
    [autoit]

    #include <Math.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;konstante
    const $rect_const=dllstructcreate("uint x; uint y; uint cols; uint rows")
    dllstructsetdata($rect_const,"cols",100)
    dllstructsetdata($rect_const,"rows",200)

    [/autoit] [autoit][/autoit] [autoit]

    ;
    $rect1=dllstructcreate("uint x; uint y; uint width; uint height")
    dllstructsetdata($rect1,"x",10)
    dllstructsetdata($rect1,"y",20)
    dllstructsetdata($rect1,"width",100)
    dllstructsetdata($rect1,"height",200)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $select=dllstructcreate("uint x; uint y; uint width; uint height")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $select=_select_und($rect1)

    [/autoit] [autoit][/autoit] [autoit]

    $x=dllstructgetdata($select,"x")
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $x = ' & $x & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $y=dllstructgetdata($select,"y")
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $y = ' & $y & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $width=dllstructgetdata($select,"width")
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $width = ' & $width & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $height=dllstructgetdata($select,"height")
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $height = ' & $height & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    func _select_und($rect)
    $a_x=dllstructgetdata($rect,"x")
    $a_y=dllstructgetdata($rect,"y")
    $a_width=dllstructgetdata($rect,"width")
    $a_height=dllstructgetdata($rect,"height")

    [/autoit] [autoit][/autoit] [autoit]

    $b_x=dllstructgetdata($rect_const,"x")
    $b_y=dllstructgetdata($rect_const,"y")
    $b_width=dllstructgetdata($rect_const,"cols")
    $b_height=dllstructgetdata($rect_const,"rows")

    [/autoit] [autoit][/autoit] [autoit]

    ;if( a.width <= 0 || a.height <= 0 ) a = Rect();
    if $a_width<=0 or $a_height<=0 then return $rect

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; _Tp x1 = std::max(a.x, b.x), y1 = std::max(a.y, b.y);
    $x1=_max($a_x,$b_x)
    $y1=_max($a_y,$b_y)

    [/autoit] [autoit][/autoit] [autoit]

    ;a.width = std::min(a.x + a.width, b.x + b.width) - x1;
    $a_width=_min($a_x+$a_width, $b_x+$b_width)-$x1

    [/autoit] [autoit][/autoit] [autoit]

    ;a.height = std::min(a.y + a.height, b.y + b.height) - y1;
    $a_height = _min($a_y + $a_height, $b_y + $b_height) - $y1;

    [/autoit] [autoit][/autoit] [autoit]

    ; a.x = x1; a.y = y1;
    dllstructsetdata($rect,"x",$x1)
    dllstructsetdata($rect,"y",$y1)
    dllstructsetdata($rect,"width",$a_width)
    dllstructsetdata($rect,"height",$a_height)
    ;if( a.width <= 0 || a.height <= 0 ) a = Rect();
    return $rect

    [/autoit] [autoit][/autoit] [autoit]

    endfunc

    [/autoit]


    wobei ich aber zugeben muss, mit Objekten wäre das ein einfaches C&P

  • Ich komme grad nicht weiter mit dieser Struktur, speziell das Element "struct".


    Wie das mit Arrays geht weiß ich ja, aber nicht, wie in diesem Fall.

    Nicht wundern, das ist fast dieselbe Struktur wie im Post #15.

  • Da ich ja mehrere Baustellen habe, hier nun die nächste.

    Ich komme einfach nicht weiter. Ich blicke da nicht durch.
    Kann mir jemand sagen, wie das in AutoIt aussieht?

    Spoiler anzeigen


    Ich bin soweit. Weiß aber jetzt nicht weiter.

    Spoiler anzeigen
    [autoit]

    ;******************************** Memory storage ****************************************/

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagCvMemBlock = _
    "ptr prev;" & _
    "ptr next"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $CV_STORAGE_MAGIC_VAL = 0x42890000

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagCvMemStorage = _
    "int signature;" & _
    "ptr bottom;" & _ ; First allocated block.
    "ptr top;" & _ ; Current memory block - top of the stack.
    "ptr parent;" & _ ; We get new blocks from parent as needed.
    "int block_size;" & _ ; Block size.
    "int free_space" ; Remaining free space in current block.

    [/autoit] [autoit][/autoit] [autoit]

    #define CV_IS_STORAGE(storage) \
    ((storage) != NULL && \
    (((CvMemStorage*)(storage))->signature & CV_MAGIC_MASK) == CV_STORAGE_MAGIC_VAL)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global Const $tagCvMemStoragePos = _
    "ptr top;" & _
    "int free_space"

    [/autoit]
  • So etwa?

    [autoit]

    Func CV_IS_STORAGE($storage)
    Return IsPtr($storage) And $storage And BitAnd(DLLStructGetData(DLLStructCreate($tagCvMemStorage, $storage), "signature"), $CV_MAGIC_MASK) = $CV_STORAGE_MAGIC_VAL
    EndFunc

    [/autoit]
  • So nach langer Zeit kann ich mich wieder OpenCV widmen.
    Momentan bin ich bei der Resize-Funktion dran.
    Dort hab ich das seltsame Verhalten bei großen Bildern, dass es diagonal versetzt ist und Linien drin sind.

    Hier das Testskript:

    Spoiler anzeigen
    [autoit]

    #include "OpenCV.au3"
    #include <WinAPIEx.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    Global $tImage, $hGui, $hBitmap, $cPic

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _OpenCV_Startup()
    $tImage = _OpenCV_LoadImage(@ScriptDir & "\KoLll.bmp")
    _OpenCV_Resize($tImage, 50)
    If @error Then MsgBox(0, "", @error)

    [/autoit] [autoit][/autoit] [autoit]

    $hGui = GUICreate("Test", 1200, 800, -1, -1, BitOR($WS_MINIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_MAXIMIZEBOX))
    $cSlider = GUICtrlCreateSlider(20, 15, 200, 40)
    GUICtrlSetLimit(-1, 100, 0)
    GUICtrlSetData(-1, 50)
    $cSliderVal = GUICtrlCreateLabel("0 %", 240, 20, 50, 17)
    $cPic = GUICtrlCreatePic("", 20, 60)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    GUICtrlSetOnEvent($cSlider, "_Resize")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $hBitmap = _CreateBitmapFromIplImage($tImage)
    _WinAPI_DeleteObject(GUICtrlSendMsg($cPic, 0x0172, 0, $hBitmap))

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(10)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    _OpenCV_ReleaseImage($tImage)
    _OpenCV_Shutdown()
    _WinAPI_DeleteObject($hBitmap)
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Resize()
    Local $_iValue = GUICtrlRead($cSlider)
    If $_iValue = 0 Then
    $_iValue = 1
    GUICtrlSetData($cSlider, $_iValue)
    EndIf
    GUICtrlSetData($cSliderVal, $_iValue & " %")
    $tImage = _OpenCV_LoadImage(@ScriptDir & "\KoLll.bmp")
    _OpenCV_Resize2($tImage, $_iValue)
    $hBitmap = _CreateBitmapFromIplImage($tImage)
    _WinAPI_DeleteObject(GUICtrlSendMsg($cPic, 0x0172, 0, $hBitmap))
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _CreateBitmapFromIplImage($_tIplImage)
    Local $_iWidth = DllStructGetData($_tIplImage, "width")
    Local $_iHeight = DllStructGetData($_tIplImage, "height")
    Local $_iDepth = DllStructGetData($_tIplImage, "depth")
    Local $_iChannels = DllStructGetData($_tIplImage, "nChannels")
    Local $_pData = DllStructGetData($_tIplImage, "imageData")

    [/autoit] [autoit][/autoit] [autoit]

    Local $_hBitmap = _WinAPI_CreateDIB($_iWidth, $_iHeight, $_iDepth * $_iChannels)
    _WinAPI_SetBitmapBits($_hBitmap, $_iWidth * $_iHeight * $_iChannels, $_pData)
    Return $_hBitmap
    EndFunc

    [/autoit]


    Die aktuelle UDF ist mit im Anhang.

    Das Bild gibts hier.

    Edit:
    Hab mal das geänderte Bild eingefügt.

  • ich hab das selbe Problem
    Bild:1920x1080x24BPP

    aber immerhin ist ein Muster dahinter, bei 97%;96% 92%;91% 87%;86% 82%;81% 77%;76% usw verschiebt es das Bild


    €: ca halb so großes Bild (1000x1000x24BPP) jetzt ist es alle 2% schräg

    Einmal editiert, zuletzt von bollen (18. Juli 2013 um 17:38)

  • Hab das Skript jetzt nicht selbst getestet aber wenn ich mir den Effekt so ansehe scheint die Breite des Zielbildes etwa 1 Pixel (damit meine ich Farbkanalpixel - kein Ganzpixel) kleiner ist als das zu schreibende Bild.
    Vielleicht auch unterschiedliche Anzahl/Größe der Farbkanäle?

  • Also AspirinJunkie hat anscheinend recht (was auch sonst ;)). Die imageSize kann ich ja aus dem Struct auslesen.

    Ich hab mal die Breite, Höhe und Kanäle ausgelesen.

    100%:
    2560 x 1600 x 3 = 12288000
    imageSize: 12288000

    34%:
    870 x 544 x 3 = 1419840
    imageSize: 1420928

    Bei Originalgröße sind die Angaben gleich. Aber bei 34% gibts schon einen Unterschied.
    Wodurch kann das kommen?

  • Hi,
    könnte sein, dass das etwas mit dem sog. Padding, also Auffüllen mit Nullbytes am Ende einer Bitmapzeile, zu tun hat.

    Die Zeilenlänge einer Bitmap (Bildbreite) muss ein durch 4 Bytes teilbarer Wert sein, dass ist bei einem 32-Bit-Farbformat ARGB zwangsläufig so, da jedes Pixel aus 4 Bytes besteht.
    Bei einem 24-Bit-Format (RGB) MUSS die Zeilenbreite durch 4 Bytes teilbar sein.
    Bsp Bildbreite = 6 Pixel, Höhe 4 Pixel, 24-Bit-Format
    24 Bit sind 3 Bytes....
    Anzahl Bytes in dieser Zeile ist 6 Pixel * 3 Byte(24 Bit) = 18 Bytes.
    Der nächstgrößere durch 4 Teilbare Wert ist 20 Bytes. Bis zu dem 20. Byte wird mit Nullbytes aufgefüllt.
    Also sieht die Zeile so aus, 20 Bytes lang:
    RGBRGBRGBRGBRGBRGB00

    Das Komplette Bild als Bitmap
    RGBRGBRGBRGBRGBRGB00
    RGBRGBRGBRGBRGBRGB00
    RGBRGBRGBRGBRGBRGB00
    RGBRGBRGBRGBRGBRGB00


    Einige Bildbearbeitungsprogramme bzw. Bildberechner fangen einen solchen "Fehler" aber nicht ab, bzw. gehen aufgrund von div. Filteralgorithmen davon aus, dass die Bilder eine durch 4 teilbare Breite haben. Dann wird von einem 32-Bitformat ausgegangen, obwohl nur ein 24-Bitformat im Bild real vorhanden ist. Was dann dazu führt, dass das letzte "Pixel" in der Zeile "aufgeteilt" wird, bzw, in die nächste Zeile verschoben wird....klaro?

    Dann wird aus unserem Beispiel oben OHNE Padding (16 Bytes breite)
    RGBRGBRGBRGBRGBR
    GBRGBRGBRGBRGBRG
    BRGBRGBRGBRGBRGB
    RGBRGBRGBRGBRGBR
    GBRGBRGB

    Zitat

    scheint die Breite des Zielbildes etwa 1 Pixel (damit meine ich Farbkanalpixel - kein Ganzpixel) kleiner ist als das zu schreibende Bild.


    Da hat dann jemand gemeint, aus 32-Bit ARGB ein 24-Bit RGB machen zu können, indem man einfach den Alphakanal "weglässt". Und ohne Padding bzw Anfügen der Nullbytes am Ende der Zeile führt das zu o.g. Problem.

  • Aaaahhaa....und was kann ich nun da machen? ?(

    Edit:
    Hab jetzt mal widthStep ausgelesen

    100%:
    7680 = 2560 x 3

    34%:
    2612 = 870 x 3 + 2
    D.h. bei 34% wurde es aufgefüllt?

    Einmal editiert, zuletzt von m-obi (18. Juli 2013 um 20:45)