I have a live webcam windows which means there are six subdivided windows in a single window live. And show pictures in colored and black and white. Is there anyway I can make the code minimalistically minimized? I believe the code is considerably long.

import cv2
import cv
import numpy as np
import matplotlib.image as mpimg
from matplotlib import pyplot as plt

def threshold_slow(T, image):
    # grab the image dimensions
    h = image.shape[0]
    w = image.shape[1]
    d = image.shape[2]
    # loop over the image, pixel by pixel
    for y in range(0, h):
        for x in range(0, w):
            for z in range(0, d):
                # threshold the pixel

                if image[y, x,z] >= T:
                    image[y, x,z] = 255
                    image[y, x,z] = 0

    # return the thresholded image
    return image
def grab_frame(cam):


    #img_counter = 0

    while True:
        ret, color1 = cam.read()
        #r = 100.0 / color1.shape[1]
        r = 640.0 / color1.shape[1]
        #r = 0.25
        dim = (100, int(color1.shape[0] * r))
        dim = (640,480)
        # perform the actual resizing of the image and show it
        color = cv2.resize(color1, dim, interpolation = cv2.INTER_AREA)

        #color = color1.copy()
        b = color.copy()
        # set green and red channels to 0
        b[:, :, 1] = 0
        b[:, :, 2] = 0

        g = color.copy()
        # set blue and red channels to 0
        g[:, :, 0] = 0
        g[:, :, 2] = 0

        r = color.copy()
        # set blue and green channels to 0
        r[:, :, 0] = 0
        r[:, :, 1] = 0

        #y= color.copy()
        #gray = cv2.cvtColor(l,cv2.COLOR_RGB2GRAY)
        #_,y = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)
        #y = cv2.cvtColor(y, cv2.COLOR_GRAY2RGB)

        y = cv2.add(r,g)

        d = color.copy()
        gray1 = cv2.cvtColor(d,cv2.COLOR_RGB2GRAY)
        _,p = cv2.threshold(gray1, 60, 255, cv2.THRESH_BINARY)
        p = cv2.cvtColor(p, cv2.COLOR_GRAY2RGB)
        return [color,b,g,r,y,p]

cam = cv2.VideoCapture(0)

    ret, color = cam.read()
    [color,b,g,r,y,p] = grab_frame(cam)
    horiz = np.hstack((color,b,g))
    #verti = np.vstack((color,r))
    horiz1 = np.hstack((r,y,p))
    verti = np.vstack((horiz,horiz1))
    cv2.imshow('HORIZONTAL', verti)

    if not ret:
    k = cv2.waitKey(1)

    if k%256 == 27:
        # ESC pressed
        print("Escape hit, closing...")



enter image description here


1 Answer 1

  • First, get rid of all the unneeded whitespace. Use consistent amount between functions (Python's official style-guide, PEP8, recommends two).

  • PEP8 also recommends using spaces in lists, after the commas, and lower_case for all variables and functions (your T in threshold_slow violates this).

  • Don't use magic numbers in your code. Give them readable names and if necessary make them global constants:

    WIDTH, HEIGHT = 640, 480
  • Next, since your images are already numpy arrays, use that fact. Your (unused) threshold_slow function can be replaced by a single line using numpy.where:

    def threshold_fast(T, image):
        return np.where(image >= T, 255, 0)

    Note that this does not modify the image inplace. It is a bad practice to do that and return a modified/new object. You should decide, either return a new object or modify in place and return None.

  • The import cv is not used (and I could not even find a way to install it anymore).

  • Tuple assignment works also without a list on the left side, just do color, b, g, r, y, p = grab_frame(cam). The same is true when returning a tuple (return color, b, g, r, y, p).

  • Arguably, I would split up your grab_frame code into subfunctions like red(image), green(image), blue(image), yellow(image), black_and_white(image).

    def red(image):
        """Copy only the red channel from image"""
        out = np.zeros_like(image)
        # for some reason red is in the last channel
        out[:, :, 2] = image[:, :, 2]
        return out

    While this move will not make your code shorter, it will make it more readable.

  • Note that the canonical order is red, green, blue (RGB). If at all possible I would stick to that. I'm not sure why openCV would deviate from that.

  • You should at least add a docstring to each of your functions as a rudimentary documentation. See above for a short example.

  • You can use while True instead of while(1). No parenthesis needed and True is unambiguous (even for those people who both know C-like languages, where 0 is False and shell scripting languages like bash, where non-zero is False).

  • I would also add a tile(images, rows) function that puts your images into rows and columns. You could just use the itertools recipe grouper for this:

    from itertools import zip_longest
    def grouper(iterable, n, fillvalue=None):
        "Collect data into fixed-length chunks or blocks"
        # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
        args = [iter(iterable)] * n
        return zip_longest(*args, fillvalue=fillvalue)
  • Since you seem to want to use different amounts of tiles, and different effects, it might make sense to keep a list of functions to apply to the base image, so that in the end you only need one call:

    def identity(x):
        return x
    def tile(images, cols, fillvalue=None):
        return np.vstack(np.hstack(group)
                         for group in grouper(images, cols, fillvalue))
    funcs = identity, red, black_and_white, canny
    images = (func(image) for func in funcs)
    # arrange them in a 2x2 grid
    cv2.imshow('HORIZONTAL', tile(images, cols=2, fillvalue=np.zeros_like(image)))

    If the number of images is not evenly divisible by the number of columns, the row is filled up with blank images.

  • You should put your main calling code under a if __name__ == "__main__" guard to allow importing from this script.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.