Esempio n. 1
0
 def startRecording(cIdx, oFormat, recFolder, fps, fSz, logFile,
                    fpsLimit, ssIntv):
     # Define the codec and create VideoWriter object
     #fourcc = cv2.VideoWriter_fourcc(*'X264')
     fourcc = cv2.VideoWriter_fourcc(*'avc1')  # for saving mp4 video
     #fourcc = cv2.VideoWriter_fourcc('x','v','i','d')
     log = "%s," % (get_time_stamp())
     log += " Cam-%.2i recording starts" % (cIdx)
     log += " [%s]" % (oFormat)
     if oFormat == 'video':
         ofn = "output_%.2i_%s.mp4" % (cIdx, get_time_stamp())
         ofn = path.join(recFolder, ofn)
         # get average of the past 10 fps records
         ofps = int(np.average(fps[:10]))
         # set 'out' as a video writer
         out = cv2.VideoWriter(ofn, fourcc, ofps, fSz, True)
         log += " [%s] [FPS: %i] [FPS-limit: %i]\n" % (ofn, ofps,
                                                       fpsLimit)
     elif oFormat == 'image':
         ofn = "output_%.2i_%s" % (cIdx, get_time_stamp())
         ofn = path.join(recFolder, ofn)
         # 'out' is used as an index of a image file
         out = 1
         log += " [%s] [Snapshot-interval: %s]\n" % (ofn, str(ssIntv))
         if not path.isdir(ofn): mkdir(ofn)
     writeFile(logFile, log)
     return out, ofn
Esempio n. 2
0
 def stopRecording(out, cIdx, logFile):
     if isinstance(out, cv2.VideoWriter): out.release()
     out = None
     ### log
     log = "%s," % (get_time_stamp())
     log += " Cam-%.2i recording stops\n" % (cIdx)
     writeFile(logFile, log)
     return out
Esempio n. 3
0
    def toggleCamThread(self, ci):
        """ Start/Stop a cam thread
        
        Args:
            ci (int): Index of cam to start
        
        Returns:
            None
        """
        if DEBUG: print("CamRecFrame.startCamThread()")

        if self.th[ci] == -1:  # thread is not running
            ### update output format for Cam recording
            cho = wx.FindWindowByName("outputFormat_cho", self.panel["ui"])
            outputFormat = cho.GetString(cho.GetSelection())  # video or image
            self.cams[ci].outputFormat = outputFormat
            if outputFormat == "video":
                ### update FPS limit for Cam recording
                w = wx.FindWindowByName("videoFPSlimit_spin", self.panel["ui"])
                fpsLimit = str2num(w.GetValue(), 'float')
                if fpsLimit != None: self.cams[ci].fpsLimit = fpsLimit
            elif outputFormat == "image":
                ### update snapshot interval for Cam recording
                w = wx.FindWindowByName("ssIntv_spin", self.panel["ui"])
                ssIntv = str2num(w.GetValue(), 'float')
                if ssIntv != None: self.cams[ci].ssIntv = ssIntv
            ### start Cam thread
            args = (
                self.q2m,
                self.q2t[ci],
                self.recFolder,
            )
            self.th[ci] = Thread(target=self.cams[ci].run, args=args)
            self.th[ci].start()
            ### start timer to check q2m
            ###   (queued message from the running thread)
            if "chkQ2M" in self.timer.keys() and \
              self.timer["chkQ2M"].IsRunning() == False:
                self.timer["chkQ2M"].Start(50)
            else:
                self.timer["chkQ2M"] = wx.Timer(self)
                self.Bind(wx.EVT_TIMER, self.chkQ2M, self.timer["chkQ2M"])
                self.timer["chkQ2M"].Start(self.dispImgRefreshIntv)
            # log message
            log = "%s, Cam-%.2i thread started\n" % (get_time_stamp(), ci)

        else:
            ### stop Cam thread
            self.q2t[ci].put("quit", True, None)  # send message to quit thread
            self.th[ci].join()
            self.th[ci] = -1
            ### if no cam thread is running, stop chkQ2M timer as well.
            if self.th == [-1] * len(self.th):
                self.timer["chkQ2M"].Stop()
            # log message
            log = "%s, Cam-%.2i thread stopped\n" % (get_time_stamp(), ci)
        writeFile(self.logFile, log)
Esempio n. 4
0
    def runImgProc(self):
        """ Run image processing going through all files 
        with all planned processing 
        
        Args: None

        Returns: None
        """
        if DEBUG: print("ImgProcsFrame.runImgProc()")

        msg = "This action will save all image files in the same"
        msg += " selected folder. If filenames are same, they will be REPLACED"
        msg += " by processed images.\n"
        msg += "Proceed?"
        dlg = PopupDialog(self, -1, "Warning", msg, 
                          flagOkayBtn=True, flagCancelBtn=True)
        if dlg.ShowModal() == wx.ID_CANCEL: return
        
        msg = "Processed files -----\n\n" # result message 
        msg4log = "" # log message
        
        ### get image file extension user wants to use 
        obj = wx.FindWindowByName("imgFormat_cho", self.panel["ui"])
        imgExt = obj.GetString(obj.GetSelection())
        if "original" in imgExt.lower(): imgExt = ""
       
        for i, fp in enumerate(self.fileList):
        # go through each file
            img = np.array(Image.open(fp)) # open image
            img = self.procImg(img) # process
            if imgExt != "":
            # if there's a specific image format user chose
                ### change file extension
                ext = "." + fp.split(".")[-1]
                if ext != imgExt: fp = fp.replace(ext, imgExt) 
            Image.fromarray(img).save(fp) # save image
            pl = str(self.procList)
            pl = pl.strip("[]").replace(", ","/").replace("'","")
            msg4log += "%s, %s, %s\n"%(get_time_stamp(), fp, pl)
            msg += "%s\n\n"%(fp)

        writeFile(self.logFile, msg4log) # logging results
        wx.MessageBox(msg, 'Results', wx.OK)
Esempio n. 5
0
    def compareSF2cParam(self, sfParams):
        """ Retrieve parameters from wx.TextCtrl in UI
        and compare parameters of the captured sound fragment with them.

        Args:
            sfParams (dict): Sound parameters of a captured sound fragment.

        Returns:
            rslt (bool): True means that two sounds matched with given 
                parameters. False means they didn't match.
            rsltTxt (str): String stored during processes of the function.
                It could be error message, information, etc.
        """ 
        if DEBUG: print("PyListenerFrame.compareSF2cParam()")
        rslt = True  # whether satisfying min. & max. value thresholds
        # of all checked parameters
        rsltTxt = ""
        tParams2c = {}  # template WAV parameters to compare

        if self.pl.templFP == None:
        # there's no selected template WAV
            _txt = "! Template WAV is not selected."
            _txt += " No comparison was conducted. !"
            rsltTxt = "[%s]"%(_txt)
            writeFile(self.logFile, "%s, [MSG], %s\n"%(get_time_stamp(), _txt))
            rslt = False
            return rslt, rsltTxt 

        else:
            mm = ["min", "max"]
            for param in self.pl.compParamList:
            # through each comparison parameter 
                name = "comp_" + param 
                chkB = wx.FindWindowByName( name+"_chk", self.panel["ip_spT"] )
                if chkB.GetValue() == False: continue  # this parameter 
                # is not checked. move on to the next parameter

                ### prepare min. and max. values (extracted from 
                ### template WAV and editted by user) to compare 
                ### with sound fragment params. 
                for mmn in mm:
                    _name = name + "_" + mmn
                    txt = wx.FindWindowByName( _name, self.panel["ip_spT"] )
                    txtVal = txt.GetValue().strip()
                    if txtVal == "":  # the textCtrl is empty
                        continue  # move to the next one, 
                        # considering this one is satisfied
                    try:
                        th = float(txtVal)  # threshold value
                    except:
                        # stop listening
                        self.onBPButtonPress('startStopListening') 
                        _txt = "%s, [MSG],"%(get_time_stamp())
                        _txt += " !!! Value of %s is not a number."%(_name)
                        _txt += " Comparison aborted. !!!\n"
                        writeFile( self.logFile, _txt)
                        show_msg(_txt)
                        rsltTxt += _txt
                        rslt = False
                        return rslt, rsltTxt 
                    tParams2c[param+"_"+mmn] = th
            if len(tParams2c) > 0:
                # compare sound fragment parmaeters 
                rslt, _txt = self.pl.compareParamsOfSF2T(sfParams, tParams2c)
                rsltTxt += "%s\n"%(_txt) 
       
        return rslt, rsltTxt 
Esempio n. 6
0
    def __init__(self):
        if DEBUG: print("ImgProcsFrame.__init__()")

        ### init frame
        w_pos = [0, 25]
        wg = wx.Display(0).GetGeometry()
        wSz = (wg[2], int(wg[3]*0.9))
        wx.Frame.__init__(
              self, 
              None, 
              -1, 
              "pyImgProc v.%s"%(__version__), 
              pos = tuple(w_pos), 
              size = tuple(wSz),
              style=wx.DEFAULT_FRAME_STYLE^(wx.RESIZE_BORDER|wx.MAXIMIZE_BOX),
                         ) 
        self.SetBackgroundColour('#333333')

        ### set app icon 
        self.tbIcon = wx.adv.TaskBarIcon(iconType=wx.adv.TBI_DOCK)
        icon = wx.Icon("icon.ico")
        self.tbIcon.SetIcon(icon)

        ##### beginning of setting up attributes ----- 
        self.w_pos = w_pos # window position
        self.wSz = wSz # window size
        self.fonts = getWXFonts(initFontSz=8, numFonts=3)
        pi = self.setPanelInfo()
        self.pi = pi # pnael information
        self.gbs = {} # for GridBagSizer
        self.panel = {} # panels
        self.timer = {} # timers
        self.selectedFolders = [] # list of selected folders
        self.fileList = [] # file list of images to process 
        self.imgFormats = [".bmp", ".eps", ".gif", 
                           ".jpg", ".pcx", ".png", 
                           ".tiff", ".webp"] # image formats for
          # saving after image processing
        self.imgFormats = sorted(self.imgFormats)
        self.imgFormats.insert(0, "Use original file extension as it is")
        self.imgProcOptions = [
                                'greyscale',
                                'crop',
                                'crop_ratio',
                                'masking',
                                'resize',
                                'resize_ratio',
                                'rotate',
                                'flip',
                                'brighten',
                                'darken',
                                'text',
                              ] # image processing options 
        self.ipParams = dict(
                                greyscale = [],
                                crop = ['x', 'y', 'w', 'h'],
                                crop_ratio = ['x', 'y', 'w', 'h'],
                                masking = ['fill-color'],
                                resize = ['w', 'h'],
                                resize_ratio = ['w', 'h'],
                                rotate = ['deg', 'expand'],
                                flip = ['direction'],
                                brighten = ['value'],
                                darken = ['value'],
                                text = ['text', 'x', 'y', 'font-size', 'color'],
                             ) # parameters for each image processing
        self.ipParamDesc = dict(
            greyscale = [],
            crop = [
                'x-coordinate to start (pixel)',
                'y-coordinate to start (pixel)',
                'width of cropped image (pixel)',
                'height of cropped image (pixel)'
                ],
            crop_ratio = [
                'x-coordinate to start (0.0-1.0)',
                'y-coordinate to start (0.0-1.0)',
                'width of cropped image (0.0-1.0)',
                'height of cropped image (0.0-1.0)'
                ],
            masking = [
                'color to fill where black in masking image (hexadecimal)',
                ],
            resize = [
                'width of image (pixel)',
                'height of image (pixel)'
                ],
            resize_ratio = [
                'width in float (1.0 = original size)',
                'height in float (1.0 = original size)',
                ],
            rotate = [
                'degree to rotate (0-360)',
                'expand to contain rotated image (0 or 1)',
                ],
            flip = [
                'direction (0-2; 0:horizontal, 1:vertical, 2:both)',
                ],
            brighten = [
                'pixel value to add'
                ],
            darken = [
                'pixel value to subtract'
                ],
            text = [
                'text to insert',
                'x-coordinate (0.0-1.0)',
                'y-coordinate (0.0-1.0)',
                'font size (integer)',
                'font color (hexadecimal)',
                ],
        ) # description of parameters
        self.ipParamVal = dict(
                                greyscale = [],
                                crop = [0, 0, 1, 1],
                                crop_ratio = [0.0, 0.0, 0.5, 0.5],
                                masking = ['#000000'], 
                                resize = [1, 1],
                                resize_ratio = [0.1, 0.1],
                                rotate = [0, 0],
                                flip = [0],
                                brighten = [20],
                                darken = [20],
                                text = ['', 0.0, 0.0, 12, '#000000'],
                              ) # default value of each parameter
        # max. number of parameters among all processes
        self.mNumParam = -1 
        for k in self.ipParams.keys():
            n = len(self.ipParams[k])
            if self.mNumParam < n: self.mNumParam = copy(n)
        self.iImgArr = None # numpy array of input image
        self.oImgArr = None # numpy array of output image
        self.logFile = "log_pyImgProc.txt"
        # extension list to recognize as an image file for processing
        self.extList = ['bmp', 'png', 'jpg', 'gif', 'pcx', 'tif', 'tiff'] 
        self.procList = [] # image processing list to execute
        self.maskFP = "mask.png" # masking image
        ##### end of setting up attributes -----  
        
        ### make log file 
        logHeader = "Timestamp, Image file name, Processes\n"
        logHeader += "# ----------------------------------------\n"
        if not path.isfile(self.logFile): # log file doesn't exist
            writeFile(self.logFile, logHeader) # write header

        ### create panels
        for pk in pi.keys():
            self.panel[pk] = SPanel.ScrolledPanel(
                                                  self, 
                                                  name="%s_panel"%(pk), 
                                                  pos=pi[pk]["pos"], 
                                                  size=pi[pk]["sz"], 
                                                  style=pi[pk]["style"],
                                                 )
            self.panel[pk].SetBackgroundColour(pi[pk]["bgCol"]) 
            #if pk in ["ip", "op"]:
            #    self.panel[pk].Bind(wx.EVT_PAINT, self.onPaint)
         
        ##### beginning of setting up UI panel interface -----
        bw = 5 # border width for GridBagSizer
        nCol = 4 # number columns
        hlSz = (pi["ui"]["sz"][0]-50, -1) # size of horizontal line separator
        vlSz = (-1, 20) # size of vertical line seprator
        self.gbs["ui"] = wx.GridBagSizer(0,0)
        row = 0
        col = 0
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Select folders",
                            name="selFolders_btn",
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        col += 1
        chk = wx.CheckBox(
                            self.panel["ui"],
                            -1,
                            label="Include sub-folders",
                            name="subFolders_chk",
                         )
        chk.SetValue(False)
        add2gbs(self.gbs["ui"], chk, (row,col), (1,1))
        row += 1; col = 0
        sTxt = setupStaticText(
                            self.panel["ui"], 
                            "Selected folders", 
                            font=self.fonts[2],
                              )
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        row += 1; col = 0
        txt = wx.TextCtrl(
                            self.panel["ui"], 
                            -1, 
                            value="[EMPTY]; Please select folders",
                            name="selDir_txt",
                            size=(hlSz[0], 75),
                            style=wx.TE_MULTILINE|wx.TE_READONLY,
                         )
        txt.SetBackgroundColour('#999999')
        add2gbs(self.gbs["ui"], txt, (row,col), (1,nCol))
        row += 1; col = 0
        add2gbs(self.gbs["ui"], 
                wx.StaticLine(self.panel["ui"],
                              -1,
                              size=hlSz,
                              style=wx.LI_HORIZONTAL),
                (row,col), 
                (1,nCol)) # horizontal line separator
        row += 1; col = 0
        lbl = "Target files (you can use wildcard characters)"
        sTxt = setupStaticText(
                            self.panel["ui"], 
                            lbl, 
                            font=self.fonts[2],
                              )
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        row += 1; col = 0
        lbl = "Allowed extensions: %s"%(str(self.extList))
        sTxt = setupStaticText(
                            self.panel["ui"], 
                            lbl, 
                            font=self.fonts[1],
                              )
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        row += 1; col = 0
        txt = wx.TextCtrl(
                            self.panel["ui"], 
                            -1, 
                            value="*.*",
                            name="targetFN_txt",
                            size=(hlSz[0], -1),
                            style=wx.TE_PROCESS_ENTER,
                         )
        txt.Bind(wx.EVT_TEXT_ENTER, self.onEnteredInTC)
        add2gbs(self.gbs["ui"], txt, (row,col), (1,nCol))
        row += 1; col = 0
        add2gbs(self.gbs["ui"], 
                wx.StaticLine(self.panel["ui"],
                              -1,
                              size=hlSz,
                              style=wx.LI_HORIZONTAL),
                (row,col), 
                (1,nCol)) # horizontal line separator
        row += 1; col = 0
        sTxt = setupStaticText(
                            self.panel["ui"], 
                            "List of files to be processed", 
                            font=self.fonts[2],
                              )
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        row += 1; col = 0
        lstCtrl = wx.ListCtrl(
                            self.panel["ui"],
                            -1,
                            name="selFile_lst",
                            size=(hlSz[0], 100),
                            style=wx.LC_REPORT|wx.LC_SINGLE_SEL,
                             ) # selected files to be processed 
        lstCtrl.AppendColumn("FilePath")
        lstCtrl.SetColumnWidth(0, lstCtrl.GetSize()[0])
        lstCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onItemSelectedInLC)
        add2gbs(self.gbs["ui"], lstCtrl, (row,col), (1,nCol))
        row += 1; col = 0
        add2gbs(self.gbs["ui"], 
                wx.StaticLine(self.panel["ui"],
                              -1,
                              size=hlSz,
                              style=wx.LI_HORIZONTAL),
                (row,col), 
                (1,nCol)) # horizontal line separator
        row += 1; col = 0
        sTxt = setupStaticText(
                            self.panel["ui"], 
                            "Processes to apply on each image", 
                            font=self.fonts[2],
                              )
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        row += 1; col = 0
        cho = wx.Choice(
                            self.panel["ui"], 
                            -1,
                            name="imgProcOption_cho",
                            choices=self.imgProcOptions,
                       )
        cho.Bind(wx.EVT_CHOICE, self.onChoice)
        add2gbs(self.gbs["ui"], cho, (row,col), (1,1))
        row += 1; col = 0
        lstCtrl = wx.ListCtrl(
                            self.panel["ui"],
                            -1,
                            name="proc_lst",
                            size=(hlSz[0], 100),
                            style=wx.LC_REPORT|wx.LC_SINGLE_SEL,
                             ) # processes to apply on each image  
        colW = lstCtrl.GetSize()[0]/(self.mNumParam+1) # set column width
        lstCtrl.AppendColumn("Process")
        for i in range(self.mNumParam):
            # add column name for parameter
            lstCtrl.AppendColumn("Param%i"%(i)) 
            lstCtrl.SetColumnWidth(i, colW)
        lstCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onItemSelectedInLC)
        add2gbs(self.gbs["ui"], lstCtrl, (row,col), (1,nCol)) 
        row += 1; col = 0
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Clear selected",
                            name="clearProc_btn",
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        col += 1
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Clear all",
                            name="clearAllProc_btn",
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        col += 1
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Move Up",
                            name="moveProcUp_btn",
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        col += 1
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Move Down",
                            name="moveProcDown_btn",
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        row += 1; col = 0
        sTxt = setupStaticText(self.panel["ui"], " ", font=self.fonts[1])
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,1))
        col += 1
        sTxt = setupStaticText(
                                self.panel["ui"], 
                                "", 
                                name="processName_sTxt",
                                font=self.fonts[1])
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,1))
        for i in range(self.mNumParam):
            row += 1; col = 0
            sTxt = setupStaticText(self.panel["ui"], 
                                   "", 
                                   name="param%i_sTxt"%(i),
                                   font=self.fonts[1])
            add2gbs(self.gbs["ui"], sTxt, (row,col), (1,3))
            sTxt.Hide()
            col += 3 
            txt = wx.TextCtrl(self.panel["ui"], 
                              -1, 
                              value="",
                              name="param%i_txt"%(i),
                              size=(100, -1))
            add2gbs(self.gbs["ui"], txt, (row,col), (1,1))
            txt.Hide()
        row += 1; col = 0
        
        col += 3
        btn = wx.Button(self.panel["ui"],
                        -1,
                        label="Update",
                        name="updateParam_btn")
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,1))
        btn.Hide()
        row += 1; col = 0
        sTxt = setupStaticText(self.panel["ui"], 
                               "File-format:", 
                               font=self.fonts[1])
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,1))
        col += 1 
        cho = wx.Choice(
                            self.panel["ui"], 
                            -1,
                            name="imgFormat_cho",
                            choices=self.imgFormats,
                       )
        add2gbs(self.gbs["ui"], cho, (row,col), (1,nCol-1))
        row += 1; col = 0
        btn = wx.Button(
                            self.panel["ui"],
                            -1,
                            label="Process & save all files",
                            name="run_btn",
                            size=(hlSz[0],-1),
                       )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row,col), (1,nCol))
        row += 1; col = 0
        sTxt = setupStaticText(self.panel["ui"], " ", font=self.fonts[1])
        add2gbs(self.gbs["ui"], sTxt, (row,col), (1,nCol))
        self.panel["ui"].SetSizer(self.gbs["ui"])
        self.gbs["ui"].Layout()
        self.panel["ui"].SetupScrolling()
        ##### end of setting up UI panel interface -----
        
        ##### beginning of setting up input image panel -----
        self.gbs["ip"] = wx.GridBagSizer(0,0)
        row = 0
        col = 0
        sBmp = wx.StaticBitmap(self.panel["ip"], name="ip_sBmp")
        add2gbs(self.gbs["ip"], sBmp, (row,col), (1,1))
        self.panel["ip"].SetSizer(self.gbs["ip"])
        self.gbs["ip"].Layout()
        self.panel["ip"].SetupScrolling()
        ##### end of setting up input image panel -----

        ##### beginning of setting up outpu image panel -----
        self.gbs["op"] = wx.GridBagSizer(0,0)
        row = 0
        col = 0
        sBmp = wx.StaticBitmap(self.panel["op"], name="op_sBmp")
        add2gbs(self.gbs["op"], sBmp, (row,col), (1,1))
        self.panel["op"].SetSizer(self.gbs["op"])
        self.gbs["op"].Layout()
        self.panel["op"].SetupScrolling()
        ##### end of setting up output image panel -----

        ### set up menu
        menuBar = wx.MenuBar()
        fileRenMenu = wx.Menu()
        selectFolders = fileRenMenu.Append(
                            wx.Window.NewControlId(), 
                            item="Select folders\tCTRL+O",
                                        )
        self.Bind(wx.EVT_MENU,
                  lambda event: self.onButtonPressDown(event, 'selectFolders'),
                  selectFolders)
        quit = fileRenMenu.Append(
                            wx.Window.NewControlId(), 
                            item="Quit\tCTRL+Q",
                                 )
        menuBar.Append(fileRenMenu, "&ImageProcessor")
        self.SetMenuBar(menuBar)
        
        ### set up hot keys
        idSelFolders = wx.Window.NewControlId()
        idQuit = wx.Window.NewControlId()
        self.Bind(wx.EVT_MENU,
                  lambda event: self.onButtonPressDown(event, 'selectFolders'),
                  id=idSelFolders)
        self.Bind(wx.EVT_MENU, self.onClose, id=idQuit)
        accel_tbl = wx.AcceleratorTable([ 
                                    (wx.ACCEL_CMD,  ord('O'), idSelFolders), 
                                    (wx.ACCEL_CMD,  ord('Q'), idQuit), 
                                        ]) 
        self.SetAcceleratorTable(accel_tbl)

        ### set up status-bar
        self.statusbar = self.CreateStatusBar(1)
        self.sbBgCol = self.statusbar.GetBackgroundColour()
        self.timer["sbTimer"] = None 

        updateFrameSize(self, wSz)

        self.Bind(wx.EVT_CLOSE, self.onClose)
Esempio n. 7
0
    def __init__(self):
        if DEBUG: print("CamRecFrame.__init__()")

        ### init frame
        w_pos = [0, 25]
        wg = wx.Display(0).GetGeometry()
        wSz = (wg[2], int(wg[3] * 0.9))
        wx.Frame.__init__(
            self,
            None,
            -1,
            "pyCamRec v.%s" % (__version__),
            pos=tuple(w_pos),
            size=tuple(wSz),
            style=wx.DEFAULT_FRAME_STYLE ^
            (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX),
        )
        self.SetBackgroundColour('#333333')

        ### set app icon
        self.tbIcon = wx.adv.TaskBarIcon(iconType=wx.adv.TBI_DOCK)
        icon = wx.Icon("icon.ico")
        self.tbIcon.SetIcon(icon)

        ##### [begin] class attributes -----
        self.logFile = "pCR_log.txt"
        self.recFolder = "recordings"
        self.w_pos = w_pos  # window position
        self.wSz = wSz  # window size
        self.fonts = getWXFonts(initFontSz=8, numFonts=3)
        self.cIndices = getCamIdx(maxNCam=4)  # indices of cams
        if self.cIndices == []:
            msg = "No usable cams is attached."
            wx.MessageBox(msg, 'Info', wx.OK | wx.ICON_INFORMATION)
            self.Destroy()
        pi = self.setPanelInfo()
        self.pi = pi  # pnael information
        self.gbs = {}  # for GridBagSizer
        self.panel = {}  # panels
        self.timer = {}  # timers
        self.cams = {}  # Cam class instances
        self.th = []  # List of threads for each cam
        self.q2m = queue.Queue()  # queue to get massage from a thread
        self.q2t = []  # list of queues to send massage to a thread
        for ci in self.cIndices:
            self.cams[ci] = Cam(self, ci, self.logFile)
            self.th.append(-1)
            self.q2t.append(queue.Queue())
        self.oCIdx = []  # opened cam indices
        self.nCOnSide = 0  # number of cam images on one side
        # each cam's frame size for displaying
        dCSz = copy(pi["rp"]["sz"])  # frame size of a cam for displaying
        self.dispCSz = dCSz
        # numpy array for displaying cam images
        self.dispArr = np.zeros(shape=(dCSz[1], dCSz[0], 3), dtype=np.uint8)
        self.is_recording = False  # whether it's currently recording or not
        self.rSTime = -1  # recording start time
        self.rDur_sTxt = None  # for showing recording duration
        self.preview_sBmp = None  # for showing preview of selected cam
        self.disp_sBmp = None  # for showing recording view of cam(s)
        self.dispImgRefreshIntv = 50  # Interval to refresh the combined frame
        # images from each cam. Increase this interval, if the image lags
        # then eventually the app gets frozen after a while.
        ##### [end] class attributes -----

        if not path.isdir(self.recFolder):  # recording folder doesn't exist
            mkdir(self.recFolder)  # make one
        if not path.isfile(self.logFile):  # log file doesn't exist
            ### make header in log file
            logHeader = "Timestamp, Message\n"
            logHeader += "#-------------------------------------------------\n"
            writeFile(self.logFile, logHeader)  # write header

        ### create panels
        for pk in pi.keys():
            self.panel[pk] = SPanel.ScrolledPanel(
                self,
                name="%s_panel" % (pk),
                pos=pi[pk]["pos"],
                size=pi[pk]["sz"],
                style=pi[pk]["style"],
            )
            self.panel[pk].SetBackgroundColour(pi[pk]["bgCol"])

        ##### beginning of setting up UI panel interface -----
        bw = 5  # border width for GridBagSizer
        nCol = 4  # number columns
        uiSz = pi["ui"]["sz"]
        hlSz = (int(uiSz[0] * 0.95), -1)  # size of horizontal line separator
        self.gbs["ui"] = wx.GridBagSizer(0, 0)
        row = 0
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Cam index: ",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, 1))
        col += 1
        _choices = [str(x) for x in self.cIndices]
        _choices.insert(0, '')
        cho = wx.Choice(
            self.panel["ui"],
            -1,
            name="camIdx_cho",
            choices=_choices,
        )
        cho.Bind(wx.EVT_CHOICE, self.onChoice)
        cho.SetSelection(0)
        add2gbs(self.gbs["ui"], cho, (row, col), (1, 1))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Initial frame image:",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, nCol))
        row += 1
        col = 0
        ### set up staticBitmap for preview
        w = int(uiSz[0] * 0.95)
        h = int(w / 1.333)
        sBmp = wx.StaticBitmap(self.panel["ui"], -1, size=(w, h))
        img = wx.Image(w, h)
        img.SetData(np.zeros((h, w, 3), dtype=np.uint8).tostring())
        sBmp.SetBitmap(img.ConvertToBitmap())
        self.preview_sBmp = sBmp
        add2gbs(self.gbs["ui"], sBmp, (row, col), (1, nCol))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Output format: ",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, 1))
        col += 1
        cho = wx.Choice(
            self.panel["ui"],
            -1,
            name="outputFormat_cho",
            choices=['video', 'image'],
        )
        cho.Bind(wx.EVT_CHOICE, self.onChoice)
        cho.SetSelection(0)
        add2gbs(self.gbs["ui"], cho, (row, col), (1, 1))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Video FPS upper limit: ",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, 2))
        col += 2
        spin = wx.SpinCtrl(
            self.panel["ui"],
            -1,
            size=(75, -1),
            min=1,
            max=60,
            initial=15,
            name='videoFPSlimit_spin',
            style=wx.SP_ARROW_KEYS | wx.SP_WRAP,
        )
        add2gbs(self.gbs["ui"], spin, (row, col), (1, 1))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Image capture interval (seconds): ",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, 2))
        col += 2
        spin = wx.SpinCtrlDouble(
            self.panel["ui"],
            -1,
            size=(75, -1),
            min=0.04,  # min; 25 fps
            max=3600,
            initial=0.5,
            inc=1,  # increment
            name='ssIntv_spin',
            style=wx.SP_ARROW_KEYS | wx.SP_WRAP,
        )
        spin.Disable()
        add2gbs(self.gbs["ui"], spin, (row, col), (1, 1))
        row += 1
        col = 0
        btn = wx.Button(
            self.panel["ui"],
            -1,
            label="Add",
            name="addCam_btn",
            size=(int(uiSz[0] * 0.463), -1),
        )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        btn.Disable()
        add2gbs(self.gbs["ui"], btn, (row, col), (1, 1))
        col += 1
        btn = wx.Button(
            self.panel["ui"],
            -1,
            label="Remove",
            name="remCam_btn",
            size=(int(uiSz[0] * 0.463), -1),
        )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        btn.Disable()
        add2gbs(self.gbs["ui"], btn, (row, col), (1, 2))
        row += 1
        col = 0
        btn = wx.Button(
            self.panel["ui"],
            -1,
            label="Remove all cams",
            name="remAllCam_btn",
            size=(int(uiSz[0] * 0.95), -1),
        )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        add2gbs(self.gbs["ui"], btn, (row, col), (1, nCol))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Cams to record (Cam index [output-format(/FPS-limit when video or /interval when image)]):",
            font=self.fonts[1],
            wrapWidth=int(uiSz[0] * 0.95),
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, nCol))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "[]",
            font=self.fonts[1],
            name="openCI_sTxt",
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, nCol))
        row += 1
        col = 0
        add2gbs(self.gbs["ui"],
                wx.StaticLine(self.panel["ui"],
                              -1,
                              size=hlSz,
                              style=wx.LI_HORIZONTAL), (row, col),
                (1, nCol))  # horizontal line separator
        row += 1
        col = 0
        btn = wx.Button(
            self.panel["ui"],
            -1,
            label="start Recording",
            name="toggleRec_btn",
            size=(int(uiSz[0] * 0.95), -1),
        )
        btn.Bind(wx.EVT_LEFT_DOWN, self.onButtonPressDown)
        btn.Disable()
        add2gbs(self.gbs["ui"], btn, (row, col), (1, nCol))
        row += 1
        col = 0
        sTxt = setupStaticText(
            self.panel["ui"],
            "Recording duration: ",
            font=self.fonts[2],
        )
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, 1))
        col += 1
        sTxt = setupStaticText(
            self.panel["ui"],
            "0:00:00",
            font=self.fonts[2],
            fgColor="#ccccff",
            bgColor="#000000",
        )
        self.rDur_sTxt = sTxt
        add2gbs(self.gbs["ui"], sTxt, (row, col), (1, nCol - 1))
        self.panel["ui"].SetSizer(self.gbs["ui"])
        self.gbs["ui"].Layout()
        self.panel["ui"].SetupScrolling()
        ##### end of setting up UI panel interface -----

        ##### beginning of setting up recording panel interface -----
        bw = 5  # border width for GridBagSizer
        self.gbs["rp"] = wx.GridBagSizer(0, 0)
        row = 0
        col = 0
        sBmp = wx.StaticBitmap(self.panel["rp"], -1, size=pi["rp"]["sz"])
        self.disp_sBmp = sBmp
        self.panel["rp"].SetSizer(self.gbs["rp"])
        self.gbs["rp"].Layout()
        self.panel["rp"].SetupScrolling()
        ##### end of setting up recording panel interface -----

        ### set up menu
        menuBar = wx.MenuBar()
        fileRenMenu = wx.Menu()
        quit = fileRenMenu.Append(
            wx.Window.NewControlId(),
            item="Quit\tCTRL+Q",
        )
        menuBar.Append(fileRenMenu, "&pyCamRec")
        self.SetMenuBar(menuBar)

        ### set up hot keys
        idQuit = wx.Window.NewControlId()
        self.Bind(wx.EVT_MENU, self.onClose, id=idQuit)
        accel_tbl = wx.AcceleratorTable([
            (wx.ACCEL_CMD, ord('Q'), idQuit),
        ])
        self.SetAcceleratorTable(accel_tbl)

        ### set up status-bar
        self.statusbar = self.CreateStatusBar(1)
        self.sbBgCol = self.statusbar.GetBackgroundColour()
        self.timer["sbTimer"] = None

        updateFrameSize(self, wSz)
        self.Bind(wx.EVT_CLOSE, self.onClose)