예제 #1
0
    def inspect(self):
        """
        Run through calibration images, showing original and undistorted.
        Intended to be run after saving calibration images.
        """
        # access calibration images
        if self.calibpath is None:
            raise RuntimeError('calibpath is unset')
        imgpath = self.calibpath + '/corners2'
        fns = [
            imgpath + '/' + f for f in listdir(imgpath)
            if f[-4:].lower() == '.jpg'
        ]
        fns.sort()
        imgs = [cv_imread(f) for f in fns]
        shape = list(imgs[0].shape)
        shape.append(len(imgs))

        # undistort
        #   go through 1-by-1 b/c asarray(imgs) gets shaped wrong & reshape messes with things
        ud = zeros(shape, dtype=uint8)
        for i in range(len(imgs)):
            ud[..., i] = self.correct(imgs[i].squeeze())

        # display side-by-side
        for i in range(len(imgs)):
            img = imgs[i].copy()
            u = ud[..., i].copy()
            cv_putText(img,
                       fns[i][-10:], (5, 15),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            cv_putText(img,
                       'Press space for next image', (5, 30),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            cv_putText(u, 'Undistort', (5, 15), 1, 1, (0, 0, 255), thickness=2)
            frame = concatenate((img, u), axis=0)
            cv_imshow('frame', frame)
            press = waitKey(-1)
            if press == ord('q'):
                break
        destroyAllWindows()
예제 #2
0
from argparse import ArgumentParser
from cv2 import destroyAllWindows, waitKey
from cv2 import imshow as cv_imshow
from cv2 import putText as cv_putText
from numpy import zeros

parser = ArgumentParser(
    description='Determine how OpenCV\'s `waitKey` interprets keypresses'
)
args = parser.parse_args()

u = zeros((240, 320, 3))  # reference frame
u1 = u.copy()             # prealloc mem
lpress = 0                # last press (`waitKey` timeout returns 255)
try:
    while 1:
        u1 = u.copy()  # avoid constant text
        cv_putText(u1, 'q to quit', (5,30), 1,1,(0,0,255), thickness=2)
        cv_putText(u1, 'Last press: %d' % lpress, (5,15), 1,1,(0,0,255), thickness=2)

        cv_imshow('win', u1)
        press = waitKey(20)
        if press == ord('q'):
            break
        if press != 255:  # `waitKey` returns 255 on timeout
            lpress = press
except Exception as e:
    raise e
finally:
    destroyAllWindows()
예제 #3
0
            break

        # Update Camera Matrix
        ncm, roi = getOptimalNewCameraMatrix(calib.cameraMatrix,
                                             calib.distCoeffs, (W, H),
                                             alpha_val)
        x, y, w, h = roi

        # Read frames and correct
        r, f = cap.read()
        if not r:
            logging.warning('Unable to read frame')
            continue
        _u1 = undistort(f,
                        calib.cameraMatrix,
                        calib.distCoeffs,
                        None,
                        newCameraMatrix=ncm)
        u1 = zeros((H, W, 3), dtype='uint8')
        u1[y:y + h, x:x + w] = _u1[y:y + h, x:x + w]
        u2 = calib.correct(f)

        cv_putText(u1, 'newCamMat', (5, 15), 1, 1, (0, 0, 255), thickness=2)
        cv_putText(u2, 'CamMat', (5, 15), 1, 1, (0, 0, 255), thickness=2)
        u = concatenate((u1, u2), axis=0)
except Exception as e:
    raise e
finally:
    cap.release()
    destroyAllWindows()
예제 #4
0
    def clean_calib_imgs(self, basepath=None, rawpath=None, cpath=None):
        """
        Provides interface to sanitize calibration images using a
        tutorial-like imshow() interface. Deletes frames, and removes elements
        from self.corners_arr, if they are not None.

        INPUTS
            (optional)
            basepath -- str -- Base path for calib frames; None
            rawpath  -- str -- Path to frames for calibration; None
            cpath    -- str -- Path to frames with chessboard; None

        NOTE
            The frames in each path must have the same name, e.g. 'f00001.jpg'

        USAGE
            SPECIFIED ONLY BASEPATH
                When all other paths the frame paths will
                be defined as:
                    rawpath = basepath + '/raw'
                    cpath = basepath + '/corners'

            PATHS TO ALL FRAMES
                If rawpath and cpath are all explicitly defined, they will be
                used as is. basepath will be ignored.
        """
        # Parse paths
        if basepath is not None:
            basepath = realpath(basepath)
            if basepath[basepath.rfind('/') + 1:] not in ('raw', 'corners',
                                                          'corners2'):
                logging.warning(
                    'Assuming \'%s\' is base dir for all unspecified frames' %
                    basepath)
                basepath = basepath
            else:
                basepath = dirname(basepath)
        if rawpath is None:
            rawpath = basepath + '/raw'
        if cpath is None:
            cpath = basepath + '/corners'

        # Select images to save
        fn_imgs = [f for f in listdir(cpath) if f[-4:].lower() == '.jpg']
        fn_imgs.sort()
        i = 0
        while i < len(fn_imgs):
            f = fn_imgs[i]
            img = cv_imread(cpath + '/' + f)
            if img is None:  # catch deleted image
                fn_imgs.pop(i)
                if self.corners_arr is not None:
                    self.corners_arr.pop(i)
                i += 1
                continue
            cv_putText(img, f, (5, 15), 1, 1, (0, 0, 255), thickness=2)
            cv_putText(img,
                       '\'r\' to remove', (5, 30),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            cv_putText(img,
                       'left bracket to go back', (5, 45),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            cv_imshow('image', img)

            # interface
            press = waitKey(-1)
            if press == ord('r'):
                fn = fn_imgs[i][fn_imgs[i].rfind('f'):]
                os_remove(rawpath + '/' + fn)
                os_remove(cpath + '/' + fn)
            elif press in (27, 81, 113):  # esc, q, Q
                break
            elif press == 91:  # left bracket
                i -= 2
            i += 1
        destroyAllWindows()
예제 #5
0
    def record_calib_imgs(self, **kwargs):
        """
        Provides photobooth-esque countdown interface. Saves frames to calib
        path in subdirectories `raw/` and `corners/`. Be sure to
        initialize the chessboard first.

        INPUTS
            (optional)
            cam       -- str/int -- camera descriptor for VideoCapture; '/dev/psEye'
            nframes   -- int     -- number of frames to record for calibration; 15
            w         -- int     -- width (px) to set camera frame; 320
            h         -- int     -- height (px) to set camera frame; 240
            fps       -- int     -- frames per second to set camera; 100
            countdown -- int     -- seconds to countdown before recording frame; 3

        EXCEPTIONS
            raises RuntimeError when chessboard hasn't been properly initialized
                by constructor or `init_chessboard`.
        """
        cam = kwargs.get('cam', '/dev/psEye')
        nframes = kwargs.get('nframes', 15)
        w = kwargs.get('w', 320)
        h = kwargs.get('h', 240)
        countdown = kwargs.get('countdown', 3)
        if type(nframes) != int:
            raise TypeError('nframes must be integer')
        if type(countdown) != int:
            raise TypeError('countdown must be integer')
        if self.img_arr is not None or self.calibpath is None:
            raise RuntimeError('Did you call init_chessboard() first?')
        cap = open_camera(cam, w, h, 100)  # this handles asserts
        self.w = int(cap.get(CAP_PROP_FRAME_WIDTH))
        self.h = int(cap.get(CAP_PROP_FRAME_HEIGHT))
        self.img_arr = zeros((self.h, self.w, 1, nframes),
                             dtype=uint8)  # raw frames
        clist = []  # corners frames
        self.corners_arr = []
        self.objpoints = []

        # Recording
        sc = 0  # "sample count"
        timer_ref = now()
        timer = lambda: 1 + int(countdown + timer_ref - now()
                                )  # countDOWN 3,2,1
        try:  # try/except to make sure camera device gets released
            img = zeros(self.img_arr.shape[:-1])  # for immediate cv_imshow
            while sc < nframes:
                # Display at top so can always exit
                cv_imshow('capture', img)
                press = waitKey(20)
                if press in (113, 81, 27):  # q, Q, esc:
                    logging.debug('quitting record')
                    break

                # Find chessboard, if possible
                ret, raw = cap.read()
                if not ret:
                    logging.error('Failed to access frame')
                    timer_ref = now()  # reset timer when things go wrong
                    continue
                gray = cvtColor(raw, COLOR_RGB2GRAY)
                corners = self._find_chessboard(gray)

                # Compute visual feedback
                if corners is None:  # alert to unfindable chessboard
                    img = raw.copy()
                    cv_putText(img,
                               'NO CHESSBOARD', (5, 15),
                               1,
                               1, (0, 0, 255),
                               thickness=2)
                    timer_ref = now(
                    )  # reset timer when chessboard isn't viable
                else:  # show countdown and progess
                    board1 = drawChessboardCorners(raw, self.boardsize,
                                                   corners, ret)
                    img = board1.copy()
                    cv_putText(img,
                               'T-%ds' % timer(), (5, 15),
                               1,
                               1, (0, 0, 255),
                               thickness=2)
                cv_putText(img,
                           '%d/%d' % (sc + 1, nframes), (5, 30),
                           1,
                           1, (0, 0, 255),
                           thickness=2)

                # Capture image
                if timer() <= 0:
                    # image saving
                    self.img_arr[..., sc] = gray.copy()[..., newaxis]
                    clist.append(board1)

                    # for camera calibration
                    self.corners_arr.append(corners)
                    self.objpoints.append(self.objp)

                    # program progess/display
                    img = zeros(raw.shape, dtype=uint8) + 255  # "flash" camera
                    sc += 1
                    timer_ref = now()

            # Save images to file
            if self.calibpath is None:
                self._create_calib_path()
            # Create save directories
            rawpath = self.calibpath + '/raw'
            cpath = self.calibpath + '/corners'
            for p in (rawpath, cpath):
                if not isdir(p):
                    if os_exists(p):
                        logging.warning(
                            '\'%s\' exists, but is not directory. Overwriting.'
                            % p)
                        os_remove(p)
                    mkdir(p)
            for i in range(nframes):
                fn_raw = rawpath + ('/f%s' % str(i + 1).zfill(5)) + '.jpg'
                fn_c = cpath + ('/f%s' % str(i + 1).zfill(5)) + '.jpg'
                cv_imwrite(fn_raw, self.img_arr[..., i],
                           (IMWRITE_JPEG_QUALITY, 100))
                cv_imwrite(fn_c, clist[i], (IMWRITE_JPEG_QUALITY, 100))

        # Close Capture
        except Exception as e:
            logging.error(e)
        finally:
            cap.release()
            destroyAllWindows()
            logging.debug('released \'%s\'' % cam)
예제 #6
0
def livetest(calibs, cam='/dev/psEye', w=320, h=240, fps=100):
    """
    Visually inspect calibrations on images actively streaming in from cam.

    INPUTS
        calibs -- str/CalibratePSEye -- fn to CSV calibrations or object with
                                        calibrations already loaded
        (optional)
        cam    -- str/int -- camera descriptor for VideoCapture; '/dev/psEye'
        w      -- int -- width (px) to set camera frame; 320
        h      -- int -- height (px) to set camera frame; 240
        fps    -- int -- frames per second to set camera; 100

    CSV FORMAT
        - delimiter: ', '
        - no floats, round and convert to int using known precision
        - strings in double quotes

    INTERFACE
        'space' to pause stream, 'q' to quit stream.
    """
    # Load calibrations if necessary
    if type(calibs) == str:
        fn = calibs  # resave to overwrite `calibs`
        calibs = CalibratePSEye()
        calibs.load_calibrations(fn)
    if type(calibs) != CalibratePSEye:
        raise RuntimeError('\'calibs\' is not type \'CalibratePSEye\'')

    # open_camera handles type asserts for camera params
    cap = open_camera(cam, w, h, fps)

    # Stream undistortion
    # try/finally to ensure cap.release() is called
    try:
        while 1:
            ret, raw = cap.read()
            if not ret:
                logging.warning('failed to read frame from \'%s\'' % cam)
            ud = calibs.correct(raw)

            # label data for user
            cv_putText(raw,
                       'Space to pause, q to quit', (5, 15),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            cv_putText(ud,
                       'undistort', (5, 15),
                       1,
                       1, (0, 0, 255),
                       thickness=2)
            total = concatenate((raw, ud), axis=0)  # 1 frame for cleanliness
            cv_imshow('total', total)

            press = waitKey(30)
            if press == ord('q'):
                break
            elif press == ord(' '):
                if waitKey(-1) == ord('q'):
                    break
    finally:
        cap.release()
        destroyAllWindows()