Jump to content

Problem with GUICtrlSetImage?


Recommended Posts

I have a directory containg images which is updated at 4 second intervals these images are snapshots from 9 different cameras. 9 Images every 4 seconds with the exception being that when each camera's limit is reached that is 15 images per camera then those images are deleted - sorta like emptying a buffer. The file naming scheme is as follows (seconds since epoch & "." & last octet of the ip address & ".jpg") I need to get the most recent frame and display it in my GUI. It must be as fast as possible because there is already a 4 second delay. This an IP Camera Viewer. I've tried the code below but its not smooth and it freezes constantly.

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=..\..\Documents and Settings\root\Desktop\CamViewer.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <Date.au3>

HotKeySet("{ESC}", "_Exit")

Global $hCamViewer, $hPic, $sCameraDir = "H:\Cam\Images"
Global $aCamera[8][3] = [[171, "", 0], [172, "", 0], [173, "", 0], [174, "", 0], [175, "", 0], [176, "", 0], [177, "", 0], [178, "", 0]]
Global Enum $iDev, $iCtrl , $iFrame
Global Enum $iGS , $iPL
FileChangeDir($sCameraDir)

_SpawnViewer()

Sleep(1000)

AdlibRegister("_UpdateViewer", 4000)

While 1
    If GUIGetMsg() == $GUI_EVENT_CLOSE Then
        Exit
    EndIf
    Sleep(50)
WEnd

Func _UpdateDisplay($iCamera)
    Local $sImage = _SetImage($iCamera)
    If $sImage <> "" Then
        GUICtrlSetImage($aCamera[$iCamera][$iCtrl], $sImage, 0, 0)
    EndIf
EndFunc

Func _UpdateViewer()
    Local $bDelay = False
    If WinGetTitle($hCamViewer, "") == "Updating..." Then
        AdlibUnRegister("_UpdateViewer")
        $bDelay = True
        While WinGetTitle($hCamViewer, "") == "Updating..."
            Sleep(500)
        WEnd
    EndIf
    WinSetTitle($hCamViewer, "", "Updating...")
    For $iCamera = 0 To 7 Step 1
        _UpdateDisplay($iCamera)
    Next
    WinSetTitle($hCamViewer, "", _Now())
    If $bDelay == True Then
        AdlibRegister("_UpdateViewer", 3000)
    EndIf
EndFunc

Func _SpawnViewer()
    Local $sFrame = ""
    $hCamViewer = GUICreate("Updating...", @DesktopWidth, @DesktopHeight, -1, -1)
    Local $iLeft = 0, $iTop = 0, $iWidth = @DesktopWidth / 4, $iHeight = @DesktopHeight / 2
    For $iCamera = 0 To 7 Step 1
        $sFrame = _SetImage($iCamera)
        While Not FileExists($sFrame)
            $sFrame = _SetImage($iCamera)
            Sleep(500)
        WEnd
        $aCamera[$iCamera][$iCtrl] = GUICtrlCreatePic($sFrame, $iLeft, $iTop, $iWidth, $iHeight)
        $iLeft += $iWidth
        If $iLeft >= @DesktopWidth Then
            $iLeft = 0
            $iTop += $iHeight
        EndIf
    Next
    GUISetState(@SW_SHOW)
    WinSetTitle($hCamViewer, "", _Now())
EndFunc

Func _RequestImage($iCamera)
    Local $hImages = FileFindFirstFile("*." & $aCamera[$iCamera][$iDev] & ".jpg")
    Local $aJPG[30], $iCount = 0
    While 1
        $aJPG[$iCount] = FileFindNextFile($hImages)
        $iCount += 1
        If @error Or $iCount == 49 Then ExitLoop
    WEnd
    Return _MostRecentFrame($aJPG)
EndFunc

Func _SetImage($iCamera)
    $aCamera[$iCamera][$iFrame] += 4
    Local $sFrame = $aCamera[$iCamera][$iFrame] & "." & $aCamera[$iCamera][$iDev] & ".jpg"
    If FileExists($sFrame) Then
        If FileExists(($aCamera[$iCamera][$iFrame] + 4) & "." & $aCamera[$iCamera][$iDev] & ".jpg") Then
            $aCamera[$iCamera][$iFrame] += 4
            $sFrame = $aCamera[$iCamera][$iFrame] & "." & $aCamera[$iCamera][$iDev] & ".jpg"
            ConsoleWrite("Camera #" & $aCamera[$iCamera][$iDev] & " Computed Frame: " & $sFrame & @CRLF)
            Return $sFrame
        EndIf
        ConsoleWrite("Camera #" & $aCamera[$iCamera][$iDev] & " Computed Frame: " & $sFrame & @CRLF)
        Return $sFrame
    EndIf
    $sFrame = _RequestImage($iCamera)
    Local $aFrame = StringSplit($sFrame, ".", 2)
    $aCamera[$iCamera][$iFrame] = $aFrame[0]
    ConsoleWrite("Camera #" & $aCamera[$iCamera][$iDev] & " Recent Frame: " & $aCamera[$iCamera][$iFrame] & @CRLF)
    Return $sFrame
EndFunc

Func _MostRecentFrame($aJPG)
    Local $iMax = 0
    For $i = 0 To UBound($aJPG, 1) -1
        If $aJPG[$i] = "" Then
            Return $aJPG[$iMax]
        EndIf
        If Int($aJPG[$i]) >= Int($aJPG[$iMax]) Then
            $iMax = $i
        EndIf
    Next
    Return $aJPG[$iMax]
EndFunc

Func _Exit()
    Exit
EndFunc

It freezes after so many seconds and not all the images will display intially. If they don't display when I run the script then they are not updated. I'm stumbed on this. Any and all help appreciated thanks.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Bump, This could be a useful script for others as well. I'm using a script on the remote computer that has access to the IP Cameras taking snapshot at a specified interval along with WinScp synchronizing the remote and local directory that contains the images. The CamViewer just takes the most recent images and displays them in a GUI. The problem is that viewer script is way to buggy.

Spoiler

censored.jpg

 

Link to comment
Share on other sites

I just commented almost every line of code in hope of recieving some help with this issue. I believe there to be a problem when using GUICtrlSetImage that is causing it to freeze.

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=..\..\Documents and Settings\root\Desktop\CamViewer.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <Date.au3>
#include <Misc.au3>

; - Only allow one instance of this script to run.
If _Singleton("CameraViewer", 1) = 0 Then
    Exit
EndIf

; - Exit upon user pressing the ESC key
HotKeySet("{ESC}", "_Exit")

; - Define the handle to the GUI and the directory that contains the images as Global variables
Global $hCamViewer, $sCameraDir = "H:\Cam\Images"
; - Global two dimensional array where the second dimension indexes are defined directly below
Global $aCamera[8][3] = [[171, "", 0], [172, "", 0], [173, "", 0], [174, "", 0], [175, "", 0], [176, "", 0], [177, "", 0], [178, "", 0]]
; - $iDev == the last octet of the IP address i. e. 171
Global Enum $iDev, _
; - $iCtrl == the handle to the image control
$iCtrl , _
; - $iFrame == the first part of the image's filename the exact time in seconds that the image was  created.
$iFrame

; - Change the script's working directory to the directory containing images
FileChangeDir($sCameraDir)

; - Create the GUI and register an Adlib Function to run periodically
_SpawnViewer()

; - Idle when other functions aren't being processed
While 1
    Sleep(50)
WEnd

Func _SpawnViewer()
    Local $sFrame = "" ; - Will contain the image's filename
    $hCamViewer = GUICreate("Updating...", @DesktopWidth, 240*2, -1, -1) ; Create a default GUI as wide as the desktop and the height is equal to the image size * 2 this allows for two rows containing 4 images
    ; - $iWidth is the desktop width divided by 4 so that when creating the picture controls, 4 images will fit evenly
    Local $iLeft = 0, $iTop = 0, $iWidth = @DesktopWidth/4, $iHeight = 240 ; $iHeight == Height of JPEG
    ; - Populate the GUI with 8 images, two rows of 4
    For $iCamera = 0 To 7 Step 1
        ; - I'm passing the number index of the $aCamera arrays first dimension to  _SetImage
        ; - $sFrame == i.e. 1366122997.172.jpg
        $sFrame = _SetImage($iCamera)
        While Not FileExists($sFrame) ; As the images are being sychronized the remote script will delete the images periodically so ensure it exist before populating the pic control
            Sleep(500) ; If it dosen't exist wait half a second and check the new image
            $sFrame = _SetImage($iCamera)
        WEnd
        ; - I think this is self explanatory
        $aCamera[$iCamera][$iCtrl] = GUICtrlCreatePic($sFrame, $iLeft, $iTop, $iWidth, $iHeight)
        ; - Adjust $iLeft by the size of each control that is created
        $iLeft += $iWidth
        ; - When the first row is complete then reset $iLeft and $iTop == the height of the first row so that the second row is directly beneath the first
        If $iLeft >= @DesktopWidth Then
            $iLeft = 0
            $iTop += $iHeight
        EndIf
    Next
    ;- Show the GUI
    GUISetState(@SW_SHOW)
    WinSetTitle($hCamViewer, "", _Now())
    ;- Give the GUI the Always on Top attribute
    WinSetOnTop($hCamViewer, "", 1)
    ; - Wait 4 seconds just because it seems to help make the images intially appear, if they don't show here then they won't be updated.....
    Sleep(4000)
    _UpdateViewer() ;- Call the update function and then register it to be called every 4 seconds from this point
    AdlibRegister("_UpdateViewer", 4000)
EndFunc


Func _UpdateViewer()
    ; - $bDelay is a switch that is being used to determine wether or not this function is registered to run periodically
    Local $bDelay = False ; - Initally it is False because we know that it is registered or will be after this function is called initally above
    ; - If the title shows "Updating..." then we know that this function is already being executed
    If WinGetTitle($hCamViewer, "") == "Updating..." Then
        ; - Log the fact that if this check wasn't being performed then two instances would be running simultaneouly which unneccessary and is what I originally thought was causing the problem
        ConsoleWrite("Encountered a delay..." & @CRLF)
        ;- Unregister this function while we wait for the other instance to finish
        AdlibUnRegister("_UpdateViewer")
        ; - Trigger the switch so we can check if it has been unregistered later
        $bDelay = True
        ;- Wait for the title to be updated indicating that the function has finished
        While WinGetTitle($hCamViewer, "") == "Updating..."
            Sleep(500)
        WEnd
    EndIf
    ; - So at this point there won't be any other instances of this function running we can update the display
    ; - Update the title which also ensures that this function won't overlap with another instance
    WinSetTitle($hCamViewer, "", "Updating...")
    ; - Update the pic controls
    For $iCamera = 0 To 7 Step 1
        _UpdateDisplay($iCamera)
    Next
    ; - Reset the window title to the current date and time
    WinSetTitle($hCamViewer, "", _Now())
    ; - If we unregisted this function then we reregister it here
    If $bDelay == True Then
        ConsoleWrite("Resuming from delay..." & @CRLF)
        AdlibRegister("_UpdateViewer", 4000)
    EndIf
EndFunc


Func _UpdateDisplay($iCamera) ; $iCamera may be 0-7
    ; $sImage contains the filename
    Local $sImage = _SetImage($iCamera)
    ; If $sImage is void or the filename dosen't exist then we won't call GUICtrlSetImage which I assume is the source of the problem.
    If $sImage <> "" And FileExists($sImage) Then
        GUICtrlSetImage($aCamera[$iCamera][$iCtrl], $sImage, 0, 0)
        ;FileDelete($sImage)
    EndIf
EndFunc

Func _SetImage($iCamera)
    ; - first I try to guess the filename of the next image that's being download to the image directory
    ;- $aCamera[$iCamera][$iFrame] == the time the picture was taken in seconds + 4
    $aCamera[$iCamera][$iFrame] += 4
    ; - this is concatenating i.e. ("1366122997" & "." & "171" & ".jpg") == 1366122997.171.jpg
    Local $sFrame = $aCamera[$iCamera][$iFrame] & "." & $aCamera[$iCamera][$iDev] & ".jpg"
    ; - If the file exists which is usually does because the images are being taken at 4 second intervals
    If FileExists($sFrame) Then
        ;- Log that information to the console and return the image's filename
        ConsoleWrite("Camera #" & $aCamera[$iCamera][$iDev] & " Computed Frame: " & $sFrame & @CRLF)
        Return $sFrame
    EndIf
    ; - If the file didn't exist didn't we need to scan the image directory and get the most recent image and return that instead
    $sFrame = _RequestImage($iCamera) ; $iCamera may be the values from 0 to 7 which is specifying the index of $aCamera's first dimension i.e. evaluates to 171
    ; I split the file name into three parts, index 0 contains the time in seconds of which the image was taken
    Local $aFrame = StringSplit($sFrame, ".", 2)
    ; - Record the time in seconds that the image was taken
    $aCamera[$iCamera][$iFrame] = $aFrame[0]
    ; - Log the information to the console
    ConsoleWrite("Camera #" & $aCamera[$iCamera][$iDev] & " Recent Frame: " & $sFrame & @CRLF)
    ; - Return the image's filename
    Return $sFrame
EndFunc

Func _RequestImage($iCamera)
    #cs
    We are searching:
    FileFindFirstFile("*." & "171" & ".jpg") or FileFindFirstFile("*.171.jpg")
    #ce
    Local $hImages = FileFindFirstFile("*." & $aCamera[$iCamera][$iDev] & ".jpg")
    ; Define an array to hold the images that are found using FileFindNextFile and store them, $iCount is the $aJPG index
    Local $aJPG[100], $iCount = 0
    ; - Loop until we've found all the images that have i.e. the 171 suffix
    While 1
        $aJPG[$iCount] = FileFindNextFile($hImages)
        $iCount += 1
        If @error Or $iCount == 49 Then ExitLoop
    WEnd
    ; Return the most recent frame...du
    Return _MostRecentFrame($aJPG)
EndFunc

; This is just doing an numerical compersion on the filenames in $aJPG where the highest value aka the most recently taken image is returned.
Func _MostRecentFrame($aJPG)
    Local $iMax = 0
    For $i = 0 To UBound($aJPG, 1) -1
        If $aJPG[$i] = "" Then
            Return $aJPG[$iMax]
        EndIf
        If Int($aJPG[$i]) >= Int($aJPG[$iMax]) Then
            $iMax = $i
        EndIf
    Next
    Return $aJPG[$iMax]
EndFunc

; Exit upon pressing the ESC key
Func _Exit()
    Exit
EndFunc
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Couple of things I see right off the bat, one is that the variable $bDelay in the function _UpdateViewer is always going to be false when the function is called. Another thing, don't use "==" for comparisons unless you plan on using strings and not booleans, "==" is a case sensitive string comparison operator.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Oops, I use javascript and other scripting languages alot so the comparison operators can get confusing... I'll make the changes and report back. Thanks

*Edit - I set $bDelay = False as a Global variable and switched all the equality comparison operators to just "=" because I don't need to do any case sensitive comparisons. It still freezes but something also worth noting is that when the script is compiled it will persist longer before it hangs. I also have used ConsoleWrite(@ScriptLineNumber) after every line of code checking to see where it freezes, the last line logged is before GUICtrlSetImage...

I took your word for the $bDelay variable but after taking a second glance there is nothing wrong with it being set to false when the function is executed because when the function is called that means that it was registered to begin with...

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

FireFox,

First, thanks for replying. :)

The these IP cameras have a web interface but I can't access them remotely. No access to the router's configuration and I think there is two of them or maybe just a switch with some fancy firmware and a core router. I keep trying to hack it with no freakin success. :mad2: So I wrote a script to download the snapshot like the multi-view web interface(I had a peek at the Javascript) at specific intervals and use WinSCP to forward those images using the SSH server I setup. Long story short is I don't have a video stream to access. If you know of a way to somehow forward the stream using SSH or some other hack that'd be cool otherwise I'd like to just find a way to stablize the code I have now. Is there anything I can use besides GUICtrlSetImage on JPEG images?

Anonymous

Spoiler

censored.jpg

 

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