PureBasic Interface to OpenCV

Developed or developing a new product in PureBasic? Tell the world about it.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 544
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: PureBasic Interface to OpenCV

Post by bbanelli »

chris319 wrote:
It's true you do have to release images that you create, but in this particular case, when you handle the image with video, you don't have to do it. Just remove it and your program won't crash while exiting.
Thanks for that. I have edited my previous post and removed it.
cvReleaseImage should be commented, not cvReleaseCapture. :)
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

cvReleaseImage should be commented, not cvReleaseCapture. :)
Corrected.
Last edited by chris319 on Tue May 26, 2015 5:10 pm, edited 1 time in total.
User avatar
JHPJHP
Addict
Addict
Posts: 2251
Joined: Sat Oct 09, 2010 3:47 am

Re: PureBasic Interface to OpenCV

Post by JHPJHP »

Hi sphinx,

You're welcome, thanks for commenting.

-------------------------------------------------------------

Hi chris319,

Great addition to the example posted by AAT - nice work.

-------------------------------------------------------------

The 64bit version of "PureBasic Interface to OpenCV" is now available for download. The 32bit version has been updated with numerous bug fixes.

Cheers!
Last edited by JHPJHP on Mon Jun 01, 2015 9:02 pm, edited 1 time in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 544
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: PureBasic Interface to OpenCV

Post by bbanelli »

JHPJHP wrote:The 64bit version of "PureBasic Interface to OpenCV" is now available for download. The 32bit version has been updated with numerous bug fixes.

NB*: The example cv_cam_chessboard_2.pb errors on the function cvCalibrateCamera2 in the 64bit interface; I think the problem may be internal to the DLL.

Cheers!
Hi JHPJHP,

brilliant as usual! :)

Speaking of real life examples, I have created a small application that enables multiple video capture with some additional OCV features. This is how it works.

http://youtu.be/qufwKpjRux8?hd=1

Naturally, it requires lots of additional work but this is kind of a "proof of concept". It was, however, rebuilt with threads (TBB) support so here are DLL's -> http://dev.banelli.biz/tmp/OCL-TBB-binaries.7z (IOW - it should be compiled with Create threadsafe executable checked)

It also uses ESCAPI to detect camera names so you will need that DLL as well! As far as I know, that is not supported in OpenCV, perhaps someone has additional insight regarding that one?

Code: Select all

XIncludeFile "includes/cv_functions.pbi"

EnableExplicit

Structure SimpleCapParams
  *mTargetBuf
  mWidth.l
  mHeight.l
EndStructure
 
PrototypeC countCaptureDevicesProc()
PrototypeC initCaptureProc(deviceno, *aParams.SimpleCapParams)
PrototypeC deinitCaptureProc(deviceno)
PrototypeC doCaptureProc(deviceno)
PrototypeC isCaptureDoneProc(deviceno)
PrototypeC getCaptureDeviceNameProc(deviceno, *namebuffer, bufferlength)
PrototypeC ESCAPIDLLVersionProc()
PrototypeC initCOMProc()

Global countCaptureDevices.countCaptureDevicesProc
Global initCapture.initCaptureProc
Global deinitCapture.deinitCaptureProc
Global doCapture.doCaptureProc
Global isCaptureDone.isCaptureDoneProc
Global getCaptureDeviceName.getCaptureDeviceNameProc
Global ESCAPIDLLVersion.ESCAPIDLLVersionProc
Global initCOM.initCOMProc

Procedure setupESCAPI()
  Protected.i capdll
  capdll = OpenLibrary(#PB_Any, "escapi.dll")
  If capdll = 0
    ProcedureReturn 0
  EndIf
  
  countCaptureDevices  = GetFunction(capdll, "countCaptureDevices")
  initCapture          = GetFunction(capdll, "initCapture")
  deinitCapture        = GetFunction(capdll, "deinitCapture")
  doCapture            = GetFunction(capdll, "doCapture")
  isCaptureDone        = GetFunction(capdll, "isCaptureDone")
  initCOM.initCOMProc  = GetFunction(capdll, "initCOM")
  getCaptureDeviceName = GetFunction(capdll, "getCaptureDeviceName")
  ESCAPIDLLVersion     = GetFunction(capdll, "ESCAPIDLLVersion")
  
  If countCaptureDevices = 0 Or initCapture = 0 Or deinitCapture = 0 Or doCapture = 0 Or isCaptureDone = 0 Or initCOM = 0 Or getCaptureDeviceName = 0 Or ESCAPIDLLVersion = 0
    ProcedureReturn 0
  EndIf
  
  If ESCAPIDLLVersion() < $200
    ProcedureReturn 0
  EndIf
  
  initCOM();  
  
  ProcedureReturn countCaptureDevices()
EndProcedure

If setupESCAPI(): Else : End 0 : EndIf

#ApplicationName = "Your Application Name"

Enumeration #PB_Event_FirstCustomValue
  #Event_ThreadMessage 
  #EventType_DetectCameras
  #EventType_ManageGadgets
  #EventType_DrawToCanvas
EndEnumeration

Enumeration
  #Window_Main
  #Window_NewProject
  #Button_NewProjectOK
  #Button_NewProjectCancel
  #ComboBox_NewProjectCanvasSize
  #SpinGadget_NewProjectHorizontal
  #SpinGadget_NewProjectVertical
  #Canvas_NewProject
  #Tree_NewProject_Cameras
  #Tree_NewProject_Texts
  #PopUpMenu_Cameras
  #PopUpMenu_Texts
  #PopUpMenu_Texts_TL
  #PopUpMenu_Texts_TR
  #PopUpMenu_Texts_BL
  #PopUpMenu_Texts_BR
  #StatusBar_Main
  #ImageGadget_Main
  #MainMenu
  #MainMenu_NewProject
  #MainMenu_SaveProject
  #MainMenu_LoadProject
  #MainMenu_CloseProject
  #MainMenu_Settings
  #MainMenu_DetectCameras
  #MainMenu_RecordPause
  #MainMenu_Exit
EndEnumeration

Structure CaptureDevices
  ID.i
  Name.s
  *capture
EndStructure

Structure VideoFrame
  *VideoFrame.IplImage
  CaptureDevice.CaptureDevices
  Font.CvFont
  Text.s
  X.i
  Y.i
  Width.i
  Height.i
  Position.s
  TextPosition.s
EndStructure

Structure VideoCanvas
  Name.s
  Width.i
  Height.i
  W.i
  H.i
  ResolutionW.i
  ResolutionH.i
EndStructure

Structure VideoText
  Position.s
  Text.s
  TextPosition.s
EndStructure

Declare CaptureFrames(*p)
Declare QuitSoftware()
Declare TreeViewExpandSubLevel(GadgetID.i, SubLevelToExpand.i)

Global NewList VideoFrames.VideoFrame(), NewList VideoDevices.CaptureDevices(), NewList VideoTexts.VideoText(), DeviceCount
Global Dim Canvases.VideoCanvas(5), Dim *Images.IplImage(1)
Global.i MainImage, DetectCamerasThr, CaptureThr, CaptureFlag = #False, WriterFlag = #False
Global *dst.IplImage
Global Dim *Images.IplImage(1)
Global *Resolution.VideoCanvas
Global *writer, WriterFileName.s = ""
Define.i Event, img
Threaded.i i, j, k

;Callback
Procedure WinProc(hWnd, msg, wParam, lParam) 
  Protected.i result
  result = #PB_ProcessPureBasicEvents 
  If msg = #WM_SYSCOMMAND
    If wparam = #SC_CLOSE
      result = 0
      QuitSoftware()
    EndIf 
  EndIf 
  ProcedureReturn result 
EndProcedure 

;Methods
Procedure MethodWindowNewProjectOK()
  Protected.i W, H, RatioW, RatioH, FrameWidth, FrameHeight
  Protected.d ResizeRatio
  W = GetGadgetState(#SpinGadget_NewProjectHorizontal)
  H = GetGadgetState(#SpinGadget_NewProjectVertical)
  RatioW = GadgetWidth(#Canvas_NewProject) / W
  RatioH = GadgetHeight(#Canvas_NewProject) / H
  ; Get First Camera settings FIXME
  ResetList(VideoDevices()) : NextElement(VideoDevices())
  FrameWidth = cvGetCaptureProperty(VideoDevices()\capture, #CV_CAP_PROP_FRAME_WIDTH)
  FrameHeight = cvGetCaptureProperty(VideoDevices()\capture, #CV_CAP_PROP_FRAME_HEIGHT)
  For i = 0 To CountGadgetItems(#Tree_NewProject_Cameras)
    If i % 2
      AddElement(VideoFrames())
      CopyStructure(GetGadgetItemData(#Tree_NewProject_Cameras, i), @VideoFrames()\CaptureDevice, CaptureDevices)
    EndIf
  Next
  *Resolution.VideoCanvas = GetGadgetItemData(#ComboBox_NewProjectCanvasSize, GetGadgetState(#ComboBox_NewProjectCanvasSize))
  *Resolution\W = W
  *Resolution\H = H
  *Resolution\ResolutionW = *Resolution\Width / W
  *Resolution\ResolutionH = *Resolution\Height / H
  *dst.IplImage = cvCreateImage(*Resolution\Width, *Resolution\Height, #IPL_DEPTH_8U, 3)
  ReDim *Images(W*H)
  ResetList(VideoFrames())
  i = 1
  MainImage = CreateImage(#PB_Any, *Resolution\Width, *Resolution\Height)
  ForEach VideoFrames()
    *Images(i - 1) = cvCreateImage(*Resolution\ResolutionW, *Resolution\ResolutionH, #IPL_DEPTH_8U, 3)
    VideoFrames()\Position = GetGadgetItemText(#Tree_NewProject_Texts, 2 * i - 2)
    VideoFrames()\TextPosition = GetGadgetItemText(#Tree_NewProject_Texts, 2 * (i - 1) + 1)
    cvInitFont(VideoFrames()\Font, #CV_FONT_HERSHEY_SIMPLEX, 1, 1, #Null, 1, #CV_AA)
    i+1
  Next
  If *Resolution\Width > WindowWidth(#Window_Main)
    ResizeRatio = *Resolution\Width / *Resolution\Height
    ResizeGadget(#ImageGadget_Main, 0, 0, Int(WindowHeight(#Window_Main) - 2 * StatusBarHeight(#StatusBar_Main)) * ResizeRatio, WindowHeight(#Window_Main) - 2 * StatusBarHeight(#StatusBar_Main))
  Else
    ResizeGadget(#ImageGadget_Main, 0, 0, *Resolution\Width, *Resolution\Height)
  EndIf
  ResetList(VideoTexts())
  ForEach VideoTexts()
    ResetList(VideoFrames())
    ForEach VideoFrames()
      If VideoFrames()\Position = VideoTexts()\Position
        VideoFrames()\Text = VideoTexts()\Text
        VideoFrames()\TextPosition = VideoTexts()\TextPosition
        Break
      EndIf
    Next
  Next
  ClearList(VideoTexts())
  CloseWindow(#Window_NewProject)
  DisableWindow(#Window_Main, #False)
  CaptureThr = CreateThread(@CaptureFrames(), 0)
  CaptureFlag = #True
  ProcedureReturn
EndProcedure
Procedure MethodWindowNewProjectCancel()
  CloseWindow(#Window_NewProject)
  DisableWindow(#Window_Main, #False)  
  ProcedureReturn
EndProcedure
Procedure MethodDrawLayoutCanvas()
  Protected.i W, H, RatioW, RatioH
  W = GetGadgetState(#SpinGadget_NewProjectHorizontal)
  H = GetGadgetState(#SpinGadget_NewProjectVertical)
  RatioW = GadgetWidth(#Canvas_NewProject) / W
  RatioH = GadgetHeight(#Canvas_NewProject) / H
  StartDrawing(CanvasOutput(#Canvas_NewProject))
  Box(0, 0, GadgetWidth(#Canvas_NewProject), GadgetHeight(#Canvas_NewProject))
  For i = 0 To W
    Line(0 + (i * RatioW), 0, 1, GadgetHeight(#Canvas_NewProject), RGB(255, 0, 0))
  Next
  For i = 0 To H
    Line(0, 0 + (i * RatioH), GadgetWidth(#Canvas_NewProject), 1, RGB(255, 0, 0))
  Next
  StopDrawing()
  ClearGadgetItems(#Tree_NewProject_Cameras)
  ClearGadgetItems(#Tree_NewProject_Texts)
  ClearList(VideoTexts())
  k = 0
  For i = 1 To W
    For j = 1 To H
      AddGadgetItem(#Tree_NewProject_Cameras, k, Str(i) + "x" + Str(j))
      SetGadgetItemData(#Tree_NewProject_Cameras, k, k)
      AddGadgetItem(#Tree_NewProject_Texts, k, Str(i) + "x" + Str(j))
      SetGadgetItemData(#Tree_NewProject_Texts, k, k)
      AddElement(VideoTexts())
      VideoTexts()\Position = Str(i) + "x" + Str(j)
      k + 1
    Next
  Next
  ProcedureReturn
EndProcedure

; Procedures
Procedure TreeViewExpandSubLevel(GadgetID.i, SubLevelToExpand.i)
  For i = 0 To CountGadgetItems(GadgetID) - 1
    If GetGadgetItemAttribute(GadgetID, i, #PB_Tree_SubLevel) <= SubLevelToExpand
      SetGadgetItemState(GadgetID, i, #PB_Tree_Expanded)
    EndIf
  Next i
EndProcedure
Procedure DetectCameras(*p)
  Protected.s TmpStr = Space(255)
  Protected.b nCreate
  Protected *capture
  
  PostEvent(#Event_ThreadMessage, #Window_Main, #PB_Ignore, #EventType_DetectCameras, 0)
  PostEvent(#Event_ThreadMessage, #Window_Main, #PB_Ignore, #EventType_ManageGadgets, 1)
  
  ClearList(VideoDevices())
  DeviceCount = setupESCAPI()
  
  For i = 0 To DeviceCount - 1
    nCreate = 0
    AddElement(VideoDevices())
    Repeat
      nCreate + 1
      *capture = cvCreateCameraCapture(i)
      If *capture
        getCaptureDeviceName(0, @TmpStr, 255)
        If PeekS(@TmpStr, -1, #PB_UTF8) <> ""
          VideoDevices()\ID = i
          VideoDevices()\Name + "#" + Str(i+1) + " " + PeekS(@TmpStr,-1,#PB_UTF8)
          VideoDevices()\capture = *capture
        EndIf
      EndIf
    Until nCreate = 5 Or *capture
  Next
  
  PostEvent(#Event_ThreadMessage, #Window_Main, #PB_Ignore, #EventType_DetectCameras, DeviceCount)
  PostEvent(#Event_ThreadMessage, #Window_Main, #PB_Ignore, #EventType_ManageGadgets, 0)
  
  ProcedureReturn
EndProcedure
Procedure CreateGadgets()
  If CreateMenu(#MainMenu, WindowID(#Window_Main))
    MenuTitle("File")
    MenuItem(#MainMenu_NewProject, "New project")
    MenuItem(#MainMenu_LoadProject, "Load project")
    MenuBar()
    MenuItem(#MainMenu_SaveProject, "Save project") : DisableMenuItem(#MainMenu, #MainMenu_SaveProject, #True)
    MenuItem(#MainMenu_CloseProject, "Close project")  : DisableMenuItem(#MainMenu, #MainMenu_CloseProject, #True)
    MenuBar()
    MenuItem(#MainMenu_Exit, "Exit")
    MenuTitle("Project")
    MenuItem(#MainMenu_RecordPause, "Record") : DisableMenuItem(#MainMenu, #MainMenu_RecordPause, #True)
    MenuBar()
    MenuItem(#MainMenu_Settings, "Settings") : DisableMenuItem(#MainMenu, #MainMenu_Settings, #True)
    MenuBar()
    MenuItem(#MainMenu_DetectCameras, "Detect cameras")
  EndIf
  If CreateStatusBar(#StatusBar_Main, WindowID(#Window_Main))
    AddStatusBarField(WindowWidth(#Window_Main))
  EndIf
  ImageGadget(#ImageGadget_Main, 0, 0, WindowWidth(#Window_Main), WindowHeight(#Window_Main) - 2 * StatusBarHeight(#StatusBar_Main),#Null)
  ProcedureReturn
EndProcedure
Procedure CreateNewProject()
  DisableWindow(#Window_Main, #True)
  If OpenWindow(#Window_NewProject, 0, 0, 640, 640, "Create new project", #PB_Window_WindowCentered | #PB_Window_Tool, WindowID(#Window_Main))
    TextGadget(#PB_Any, 10, 13, 100, 20, "Video canvas size")
    ComboBoxGadget(#ComboBox_NewProjectCanvasSize, 120, 10, 120, 20)
    For i = 0 To ArraySize(Canvases())
      AddGadgetItem(#ComboBox_NewProjectCanvasSize, i, Canvases(i)\Name)
      SetGadgetItemData(#ComboBox_NewProjectCanvasSize, i, @Canvases(i))
    Next
    SetGadgetState(#ComboBox_NewProjectCanvasSize, 0)
    TextGadget(#PB_Any, 260, 13, 100, 20, "Horizontal tiles")
    SpinGadget(#SpinGadget_NewProjectHorizontal, 360, 10, 40, 20, 1, 16, #PB_Spin_Numeric) : SetGadgetState(#SpinGadget_NewProjectHorizontal, 1)
    TextGadget(#PB_Any, 420, 13, 100, 20, "Vertical tiles")
    SpinGadget(#SpinGadget_NewProjectVertical, 520, 10, 40, 20, 1, 16, #PB_Spin_Numeric) : SetGadgetState(#SpinGadget_NewProjectVertical, 1)
    TextGadget(#PB_Any, 10, 40, 100, 20, "Pick cameras")
    TreeGadget(#Tree_NewProject_Cameras, 10, 70, 200, 170) : GadgetToolTip(#Tree_NewProject_Cameras, "Right click to assign camera to frame.")
    TextGadget(#PB_Any, 220, 40, 100, 20, "Assign text")
    TreeGadget(#Tree_NewProject_Texts, 220, 70, 200, 170)
    CanvasGadget(#Canvas_NewProject, 10, 260, 620, 340)
    MethodDrawLayoutCanvas()
    ButtonGadget(#Button_NewProjectOK, 210, 610, 100, 20, "OK")
    ButtonGadget(#Button_NewProjectCancel, 330, 610, 100, 20, "Cancel")
  EndIf
  ProcedureReturn
EndProcedure
Procedure CaptureFrames(*p)
  Protected.i FrameWidth, FrameHeight
  Protected.d RowNumber, ColumnNumber
  While CaptureFlag = #True
    ResetList(VideoFrames())
    RowNumber = ListSize(VideoFrames()) / *Resolution\W
    ColumnNumber = ListSize(VideoFrames()) / *Resolution\H
    i = 0
    ForEach VideoFrames()
      FrameWidth = *Images(i)\width
      FrameHeight = *Images(i)\height
      VideoFrames()\X = Mod(i,ColumnNumber) * FrameWidth
      VideoFrames()\Y = Round(i/ColumnNumber, #PB_Round_Down) * FrameHeight
      VideoFrames()\Width = FrameWidth
      VideoFrames()\Height = FrameHeight      
      VideoFrames()\VideoFrame = cvQueryFrame(VideoFrames()\CaptureDevice\capture)
      cvResize(VideoFrames()\VideoFrame, *Images(i), #CV_INTER_AREA)
      If VideoFrames()\TextPosition = "Top left"
        If VideoFrames()\Text = "TimeDate()"
          cvPutText(*Images(i), FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss", Date()), 10, 30, VideoFrames()\Font, 0, 0, 255, 0)
        Else
          cvPutText(*Images(i), VideoFrames()\Text, 10, 30, VideoFrames()\Font, 0, 0, 255, 0)
        EndIf
      ElseIf VideoFrames()\TextPosition = "Top right"
        If VideoFrames()\Text = "TimeDate()"
          cvPutText(*Images(i), FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss", Date()), FrameWidth - 200, 30, VideoFrames()\Font, 0, 0, 255, 0)
        Else
          cvPutText(*Images(i), VideoFrames()\Text, FrameWidth - 200, 30, VideoFrames()\Font, 0, 0, 255, 0)
        EndIf
      ElseIf VideoFrames()\TextPosition = "Bottom left"
        If VideoFrames()\Text = "TimeDate()"
          cvPutText(*Images(i), FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss", Date()), 10, FrameHeight - 20, VideoFrames()\Font, 0, 0, 255, 0)
        Else
          cvPutText(*Images(i), VideoFrames()\Text, 10, FrameHeight - 20, VideoFrames()\Font, 0, 0, 255, 0)
        EndIf
      ElseIf VideoFrames()\TextPosition = "Bottom right"
        If VideoFrames()\Text = "TimeDate()"
          cvPutText(*Images(i), FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss", Date()), FrameWidth - 200, FrameHeight - 20, VideoFrames()\Font, 0, 0, 255, 0)
        Else
          cvPutText(*Images(i), VideoFrames()\Text, FrameWidth - 200, FrameHeight - 20, VideoFrames()\Font, 0, 0, 255, 0)
        EndIf
      EndIf
      cvFlip(*Images(i), #Null, 0)
      cvSetImageROI(*dst, Mod(i,ColumnNumber) * FrameWidth, Round(i/ColumnNumber, #PB_Round_Down) * FrameHeight, FrameWidth, FrameHeight)
      cvAndS(*Images(i), 0, 0, 0, 0, *dst, #Null)
      cvAdd(*dst, *Images(i), *dst, #Null)
      cvResetImageROI(*dst)
      i + 1
    Next
    cvFlip(VideoFrames()\VideoFrame, #Null, 0)
    StartDrawing(ImageOutput(MainImage))
    DrawImage(ImageID(MainImage),0,0)
    CopyMemory(*dst\imageData, DrawingBuffer(), *dst\width * *dst\height * 3)
    StopDrawing()    
    ResizeImage(MainImage, GadgetWidth(#ImageGadget_Main), GadgetHeight(#ImageGadget_Main))
    If WriterFlag
      cvFlip(*dst, #Null, 0)
      cvWriteFrame(*writer, *dst)
    EndIf      
    PostEvent(#Event_ThreadMessage, #Window_Main, #PB_Ignore, #EventType_DrawToCanvas, #PB_Ignore)   
    Delay(40)
  Wend
  ProcedureReturn
EndProcedure
Procedure QuitSoftware()
  If IsThread(DetectCamerasThr)
    KillThread(DetectCamerasThr)
  EndIf
  WriterFlag = #False
  If IsThread(CaptureThr)
    WaitThread(CaptureThr, 40)
    cvReleaseVideoWriter(@*writer)
    CaptureFlag = #False
    WaitThread(CaptureThr, 40)
  EndIf
  ResetList(VideoDevices())
  ForEach VideoDevices()
    cvReleaseCapture(@VideoDevices()\capture)
  Next
  FreeList(VideoDevices())
  If IsThread(CaptureThr)
    KillThread(CaptureThr)
  EndIf
  End 0
  ProcedureReturn
EndProcedure
Procedure CameraPopUpMenuEvent()
  Protected.i CurrentTreePosition
  Protected.s MenuItemText
  CurrentTreePosition = GetGadgetState(#Tree_NewProject_Cameras)
  MenuItemText = GetMenuItemText(#PopUpMenu_Cameras, EventMenu())
  AddGadgetItem(#Tree_NewProject_Cameras, CurrentTreePosition + 1, MenuItemText, #Null, 1)
  ResetList(VideoDevices())
  ForEach VideoDevices()
    If VideoDevices()\Name = MenuItemText
      Break
    EndIf
  Next
  SetGadgetItemData(#Tree_NewProject_Cameras, CurrentTreePosition + 1, @VideoDevices())
  SetGadgetItemState(#Tree_NewProject_Cameras, CurrentTreePosition + 1, #PB_Tree_Expanded)
  TreeViewExpandSubLevel(#Tree_NewProject_Cameras, 1)
  ProcedureReturn
EndProcedure
Procedure TextsPopUpMenuEvent()
  Protected.i CurrentTreePosition
  Protected.s MenuItemText, Position
  CurrentTreePosition = GetGadgetState(#Tree_NewProject_Texts)
  MenuItemText = GetMenuItemText(#PopUpMenu_Texts, EventMenu())
  Position = GetGadgetItemText(#Tree_NewProject_Texts, CurrentTreePosition)
  AddGadgetItem(#Tree_NewProject_Texts, CurrentTreePosition + 1, MenuItemText, #Null, 1)    
  TreeViewExpandSubLevel(#Tree_NewProject_Texts, 1)
  ResetList(VideoTexts())
  ForEach VideoTexts()
    If VideoTexts()\Position = Position
      VideoTexts()\TextPosition = MenuItemText
      VideoTexts()\Text = InputRequester("Please enter text", "Please enter text for camera on position " + Position, "Camera x")
      Break
    EndIf
  Next
  ProcedureReturn
EndProcedure
Procedure CreateCanvases()
  Canvases(0)\Name = "DV PAL - 720x576"
  Canvases(0)\Width = 720
  Canvases(0)\Height = 576
  Canvases(1)\Name = "DV NTSC - 720x480"
  Canvases(1)\Width = 720
  Canvases(1)\Height = 480
  Canvases(2)\Name = "D4 - 1440x1024"
  Canvases(2)\Width = 1440
  Canvases(2)\Height = 1024
  Canvases(3)\Name = "D16 - 2880x2048"
  Canvases(3)\Width = 2880
  Canvases(3)\Height = 2048
  Canvases(4)\Name = "720p - 1280x720"
  Canvases(4)\Width = 1280
  Canvases(4)\Height = 720
  Canvases(5)\Name = "1080p - 1920x1080"
  Canvases(5)\Width = 1920
  Canvases(5)\Height = 1080  
  ProcedureReturn
EndProcedure

; OnThread Messages
Procedure OnThreadMessage()
  Select EventType()
    Case #EventType_DetectCameras
      If EventData()
        StatusBarText(#StatusBar_Main, 0, "Detected " + Str(EventData()) + " camera(s).")
        If CreatePopupMenu(#PopUpMenu_Cameras)
          i = 1000
          ResetList(VideoDevices())
          ForEach VideoDevices()
            MenuItem(i, VideoDevices()\Name)
            BindMenuEvent(#PopUpMenu_Cameras, i, @CameraPopUpMenuEvent())
            i + 1
          Next
        EndIf
        If CreatePopupMenu(#PopUpMenu_Texts)
          MenuItem(#PopUpMenu_Texts_TL, "Top left")
          MenuItem(#PopUpMenu_Texts_TR, "Top right")
          MenuItem(#PopUpMenu_Texts_BL, "Bottom left")
          MenuItem(#PopUpMenu_Texts_Br, "Bottom right")
          For i = #PopUpMenu_Texts_TL To #PopUpMenu_Texts_BR
            BindMenuEvent(#PopUpMenu_Texts, i, @TextsPopUpMenuEvent())
          Next
        EndIf
      Else
        StatusBarText(#StatusBar_Main, 0, "Detecting cameras, stand by...")
      EndIf
    Case #EventType_ManageGadgets
      If EventData() = 0
        For i = #MainMenu_NewProject To #MainMenu_RecordPause
          DisableMenuItem(#MainMenu, i, #False)
        Next
      ElseIf EventData() = 1
        For i = #MainMenu_NewProject To #MainMenu_RecordPause
          DisableMenuItem(#MainMenu, i, #True)
        Next        
      EndIf
    Case #EventType_DrawToCanvas
      SetGadgetState(#ImageGadget_Main, ImageID(MainImage))
  EndSelect
  ProcedureReturn
EndProcedure 

If OpenWindow(#Window_Main, 0, 0, 1024, 768, #ApplicationName, #PB_Window_Maximize | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
  
  SetWindowCallback(@WinProc(), #Window_Main)
  
  CreateGadgets()
  CreateCanvases()
  
  BindEvent(#Event_ThreadMessage, @OnThreadMessage())
  
  DetectCamerasThr = CreateThread(@DetectCameras(), 0)
  
  Repeat
    Event = WaitWindowEvent()
    
    Select Event
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Tree_NewProject_Cameras
            Select EventType()
              Case #PB_EventType_RightClick
                DisplayPopupMenu(#PopUpMenu_Cameras, WindowID(#Window_NewProject))
            EndSelect
          Case #Tree_NewProject_Texts
            Select EventType()
              Case #PB_EventType_RightClick
                DisplayPopupMenu(#PopUpMenu_Texts, WindowID(#Window_NewProject))
            EndSelect
          Case #SpinGadget_NewProjectHorizontal
            Select EventType()
              Case #PB_EventType_Change
                MethodDrawLayoutCanvas()
            EndSelect
          Case #SpinGadget_NewProjectVertical
            Select EventType()
              Case #PB_EventType_Change
                MethodDrawLayoutCanvas()
            EndSelect
          Case #Button_NewProjectOK
            MethodWindowNewProjectOK()
          Case #Button_NewProjectCancel
            MethodWindowNewProjectCancel()
        EndSelect
        
      Case #PB_Event_Menu
        Select EventMenu()
          Case #MainMenu_NewProject : CreateNewProject()
          Case #MainMenu_DetectCameras
            If IsThread(DetectCamerasThr) = 0
              DetectCamerasThr = CreateThread(@DetectCameras(), 0)
            EndIf
          Case #MainMenu_RecordPause
            WriterFileName = SaveFileRequester("Save video", "Video.avi", "AVI (*.avi)|*.avi", 0)
            If WriterFileName
              *writer = cvCreateVideoWriter(WriterFileName, CV_FOURCC("D", "I", "V", "X"), 7, *Resolution\Width, *Resolution\Height, #True)
              If Not *writer : cvCreateVideoWriter(WriterFileName, CV_FOURCC("M", "S", "V", "C"), 7, *Resolution\Width, *Resolution\Height, #True) : EndIf
              WriterFlag = #True
            EndIf
          Case #MainMenu_Exit : QuitSoftware()
        EndSelect
        
    EndSelect
  Until Event = #PB_Event_CloseWindow
EndIf
Last edited by bbanelli on Tue May 26, 2015 1:53 pm, edited 1 time in total.
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
AAT
Enthusiast
Enthusiast
Posts: 259
Joined: Sun Jun 15, 2008 3:13 am
Location: Russia

Re: PureBasic Interface to OpenCV

Post by AAT »

Hi JHPJHP!
Thank you for your work and for sharing!
--------------------------------------
In numerous examples of the JHPJHP pack you can see next sequence of operands:

Code: Select all

...
  cvNamedWindow(#CV_WINDOW_NAME, #CV_WINDOW_AUTOSIZE)
  window_handle = cvGetWindowHandle(#CV_WINDOW_NAME)
  hWnd = GetParent_(window_handle)
  ShowWindow_(hWnd, #SW_HIDE)
  OpenWindow(0, 0, 0, FrameWidth, FrameHeight + 60, #CV_WINDOW_NAME, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   SetParent_(window_handle, WindowID(0))
...
It make possible to show openCV window in the PB window at position x=1, y=1.
I needed to change position of the openCV window and i found this solution:

Code: Select all

IncludeFile "includes/cv_functions.pbi"

#CV_WINDOW_NAME = "OpenCV Window"

Repeat
  nCreate + 1
  *capture = cvCreateCameraCapture(0)
Until nCreate = 5 Or *capture

If Not *capture
  MessageRequester("Error!", "WebCam not found!")
Else 
  FrameWidth = cvGetCaptureProperty(*capture, #CV_CAP_PROP_FRAME_WIDTH)
  FrameHeight = cvGetCaptureProperty(*capture, #CV_CAP_PROP_FRAME_HEIGHT)
  
  WinWidth = 800
  WinHeight = 600    
  If WinWidth < FrameWidth + 20
    WinWidth = FrameWidth + 20
  EndIf
  If WinHeight < FrameHeight + 20
    WinHeight = FrameHeight + 20
  EndIf
  cvNamedWindow(#CV_WINDOW_NAME, #CV_WINDOW_NORMAL)
  cvResizeWindow(#CV_WINDOW_NAME, FrameWidth, FrameHeight)
  window_handle = cvGetWindowHandle(#CV_WINDOW_NAME)
  hWnd = GetParent_(window_handle)
  ShowWindow_(hWnd, #SW_HIDE)
  
  OpenWindow(0, 0, 0, WinWidth, WinHeight, "Main Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  OpenWindow(1, 0, 0, FrameWidth, FrameHeight, "Child Window", #PB_Window_BorderLess)
  
  SetParent_(WindowID(1), WindowID(0))  
  SetParent_(window_handle, WindowID(1))    
  MoveWindow_(WindowID(1), WinWidth-FrameWidth-10, WinHeight-FrameHeight-10, FrameWidth, FrameHeight, 1)   
  
  Repeat
    event = WaitWindowEvent(1)      
    *image.IplImage = cvQueryFrame(*capture)
    If *image
      cvLine(*image, 0, FrameHeight/2, FrameWidth-1, FrameHeight/2, 50, 50, 255, 0, 1, #CV_AA, 0)  
      cvLine(*image, FrameWidth/2, 0, FrameWidth/2, FrameHeight-1, 50, 50, 255, 0, 1, #CV_AA, 0) 
      cvCircle(*image, FrameWidth/2, FrameHeight/2, 50, 50, 50, 255, 0, 1, #CV_AA, 0)
      cvShowImage(#CV_WINDOW_NAME, *image)               
    EndIf
    cvWaitKey(1)
  Until event = #PB_Event_CloseWindow
  cvDestroyWindow(#CV_WINDOW_NAME)    
  cvReleaseCapture(@*capture)
I have little skills in WinAPI, therefore it took some time...

The second solution - without WinAPI

Code: Select all

IncludeFile "includes/cv_functions.pbi"

Enumeration 100
  #CamFrameID 
  #ImgGadgetID
  #CatchedImgID
EndEnumeration

Repeat
  nCreate + 1
  *capture = cvCreateCameraCapture(0)
Until nCreate = 5 Or *capture

If Not *capture
  MessageRequester("Error!", "WebCam not found!")
Else  
  imgWidth = cvGetCaptureProperty(*capture, #CV_CAP_PROP_FRAME_WIDTH)
  imgHeight = cvGetCaptureProperty(*capture, #CV_CAP_PROP_FRAME_HEIGHT)
  
  WinWidth = 800
  WinHeight = 600
  If WinWidth < imgWidth + 20
    WinWidth = imgWidth + 20
  EndIf
  If WinHeight < imgHeight + 20
    WinHeight = imgHeight + 20
  EndIf
  imgPosX = WinWidth - imgWidth - 10
  imgPosY = WinHeight - imgHeight - 10
  
  CreateImage(#CamFrameID, imgWidth, imgHeight)
  OpenWindow(0, 0, 0, WinWidth, WinHeight, "Main Window", #PB_Window_SystemMenu  | #PB_Window_ScreenCentered)
  ImageGadget(#ImgGadgetID, imgPosX, imgPosY, imgWidth, imgHeight, ImageID(#CamFrameID))
  
  Repeat
    event = WaitWindowEvent(1)    
    *image.IplImage = cvQueryFrame(*capture)     
    If *image    
      cvLine(*image, 0, imgHeight/2, imgWidth-1, imgHeight/2, 50, 50, 255, 0, 1, #CV_AA, 0)  
      cvLine(*image, imgWidth/2, 0, imgWidth/2, imgHeight-1, 50, 50, 255, 0, 1, #CV_AA, 0) 
      cvCircle(*image, imgWidth/2, imgHeight/2, 50, 50, 50, 255, 0, 1, #CV_AA, 0)           
      *mat.CvMat = cvEncodeImage(".bmp", *image, 0)          
      CatchImage(#CatchedImgID, *mat\ptr)          
      SetGadgetState(#ImgGadgetID, ImageID(#CatchedImgID)) 
      FreeImage(#CatchedImgID)      
      cvReleaseMat(@*mat)       
    EndIf  
  Until event = #PB_Event_CloseWindow
  cvReleaseCapture(@*capture)
EndIf  
Good luck!
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

There are two ways to implement the 'scope in my example: one is to use an image gadget; the other is to draw the image directly onto the window. If the window goes behind another, the image is being refreshed every 1/30 or 1/60 second, so there is no need for manual refresh. Which would be preferable/more efficient?

This might be asking a lot, but it would be nice if opencv clipped video values of 0 and 255 as they are forbidden values in Rec.709, like so:

Code: Select all

If value > 254: value = 254:elseif value < 1: value = 1:endif
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

In high-end video, Rec.709 specifies that digital code 16 shall be reference black, with codes 1 to 15 acting as "footroom". Digital code 235 shall be reference white, with codes 236 to 254 acting as "headroom". Codes 0 and 255 are used as sync and are not allowed.

http://en.wikipedia.org/wiki/Rec._709#D ... esentation
User avatar
JHPJHP
Addict
Addict
Posts: 2251
Joined: Sat Oct 09, 2010 3:47 am

Re: PureBasic Interface to OpenCV

Post by JHPJHP »

Hi bbanelli,

Thank you for your comments, interest and support.

I just tried your application, and it has a lot of potential. You're correct OpenCV doesn't support camera names, but maybe an index would work:
- nCapture will need to be stored (list, array, etc.)

Code: Select all

Repeat
  *capture = cvCreateCameraCapture(nCapture)

  If Not *capture : Break : Else : nCapture + 1 : EndIf

  cvReleaseCapture(@*capture)
ForEver
cvReleaseCapture(@*capture)
*capture = cvCreateCameraCapture(nCapture - 1)
------------------------------------------------------------------------

Hi AAT,

You're very much welcome.

Thank you for the code examples and invaluable support.

------------------------------------------------------------------------

Hi chris319,

The following may be what you're looking for: cvCvtColor
- additional information

See the example: cv_cvtcolor.pb
- hit the spacebar until the heading reads "XYZ"

------------------------------------------------------------------------

I've compiled an "OpenCV 3.0 RC1" PureBasic (x86 / x64) interface package, but encountered some issues.
- I'm holding off posting an additional link until the final version of OpenCV 3.0 is released, and only if the problems are fixed or I find a way around them

NB*: Currently I have no plans on replacing 2.4.11 with 3.0 due to the changes in setup and support.

While working with "OpenCV 3.0 RC1" I noticed a new function was added (from version 2.4.10 - current):

Code: Select all

cvSetTrackbarMax(trackbar_name.p-ascii, window_name.p-ascii, maxval)
I've updated the existing downloads, but instead of downloading both packages again, you can just add the above declaration to: cv_functions.pbi.
- new function should be placed before: cvSetTrackbarPos

Cheers.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

Speaking of real life examples, I have created a small application that enables multiple video capture with some additional OCV features.
I tried it. It compiled OK but crashed with an "invalid memory access" error and again with a "pointer is null" error. "Create threadsafe executable" was checked.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 544
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: PureBasic Interface to OpenCV

Post by bbanelli »

JHPJHP wrote:Hi bbanelli,

Thank you for your comments, interest and support.

I just tried your application, and it has a lot of potential. You're correct OpenCV doesn't support camera names, but maybe an index would work:
- nCapture will need to be stored (list, array, etc.)

Code: Select all

Repeat
  *capture = cvCreateCameraCapture(nCapture)

  If Not *capture : Break : Else : nCapture + 1 : EndIf

  cvReleaseCapture(@*capture)
ForEver
cvReleaseCapture(@*capture)
*capture = cvCreateCameraCapture(nCapture - 1)
Thanks for the tip (and all the hard work you've done so far for us!), I'll look into this. :)
I've compiled an "OpenCV 3.0 RC1" PureBasic (x86 / x64) interface package, but encountered some issues.
- I'm holding off posting an additional link until the final version of OpenCV 3.0 is released, and only if the problems are fixed or I find a way around them

NB*: Currently I have no plans on replacing 2.4.11 with 3.0 due to the changes in setup and support.
It seems that 3.0 is mostly incompatible with your previous work, right? Will it generally be possible at all to work with 3.0 in PB, as far as I can see, they seem to be forcing C++ pretty hard in it...
chris319 wrote:
Speaking of real life examples, I have created a small application that enables multiple video capture with some additional OCV features.
I tried it. It compiled OK but crashed with an "invalid memory access" error and again with a "pointer is null" error. "Create threadsafe executable" was checked.
Hi chris319,

are you sure your include files are also compiled with "Create threadsafe executable"? Since I've deployed a bit advanced version to several very different computers and it works without a problem. And naturally, you have to use my DLL's since they are recompiled with Intel's TBB to support multithreading. I am rather sure that ESCAPI is not thread safe, but since it is used only once in initialization, perhaps that's not even important (please someone correct me if I'm wrong in general).
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
User avatar
JHPJHP
Addict
Addict
Posts: 2251
Joined: Sat Oct 09, 2010 3:47 am

Re: PureBasic Interface to OpenCV

Post by JHPJHP »

Hi bbanelli,

You're welcome.
bbanelli wrote:It seems that 3.0 is mostly incompatible with your previous work, right?
On the contrary OpenCV 3.0 is mostly compatible with the PureBasic interface, but there are some issues.
- the legacy functions have been excluded, but may return in the official release as well as the division of modules
- the functions needed to run the example cv_cam_motionhistory.pb have been removed (moved to legacy)
- in the 64bit version of the interface the function cvGetSize returns an error [ RESOLVED ]
- the "webcam" examples either don't connect or return a black screen

-------------------------------------------------------

Hi bbanelli, chris319,
chris319 wrote:I tried it. It compiled OK but crashed with an "invalid memory access" error and again with a "pointer is null" error.
I experienced the same crash by creating a project without first adding a camera, or adding too many cameras.
Last edited by JHPJHP on Tue Jun 02, 2015 11:22 pm, edited 5 times in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

bbanelli: I got it to work by selecting File->New Project, then right clicking on "1x1" and selecting my camera after the tooltip appeared. My camera's output appeared on the screen and I was able to create an .avi file. The .avi file caused VLC to crash when I tried to play it back.

The user interface could be a bit more intuitive.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

The thread about a webm recorder has been moved by the moderators to "Coding Questions".

I have a simple audio recorder which encodes to opus, but must clean it up and make sure the buffer contains a fixed number of samples.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: PureBasic Interface to OpenCV

Post by chris319 »

I don't know if this helps, but it's an interesting find:

http://www.wischik.com/lu/programmer/av ... l#examples
User avatar
JHPJHP
Addict
Addict
Posts: 2251
Joined: Sat Oct 09, 2010 3:47 am

Re: PureBasic Interface to OpenCV

Post by JHPJHP »

Updated (x86 / x64):
- Structures, Procedures, and Functions
- improved all the examples that use the Functions: cvCreateHist, cvCalcHist / cvCalcArrHist
-- previously the examples only accepted a single range, but now accept an array of ranges
- fixed the 64bit version of: cv_cam_chessboard_2.pb

OpenCV 3.0 RC1
- the binaries have been released as a World module (single DLL and LIB file)
- the World module became official in version 2.4.7, but the binaries needed building from source

I've created an interface to the latest OpenCV 3.0 RC1 x86 / x64 binaries, but encountered the following issues:
JHPJHP wrote:- the legacy functions have been excluded, but may return in the official release as well as the division of modules
- the functions needed to run the example cv_cam_motionhistory.pb have been removed (moved to legacy)
- in the 64bit version of the interface the function cvGetSize returns an error [ RESOLVED ]
- the "webcam" examples either don't connect or return a black screen
NB*: I've sent an email to "OpenCV Admin" concerning the webcam problem mentioned above, but I'm not sure they put a priority on their C interface.

-----------------------------------------------------------------------------------------------------

Applied a global find / replace to all the examples:
- replaced cvDestroyWindow with cvDestroyAllWindows

NB*: I've updated all the Dropbox links in my various "Tricks 'n' Tips" posts to direct download by replacing the following section of the URL: "www.dropbox.com" with "dl.dropboxusercontent.com"

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
Locked