OpenCV upscales webcam's feed instead of using full resolution

Viewed 355

I have a 1080p webcam (Logitech v-u0032) and I am creating program that saves still from it's feed every X seconds, however images have black bars on sides and resolution is seemingly lower than still taken with Windows built in camera app, both output file that has 1920x1080 pixels but difference in actual resolution is very visible

I've searched for ways to change the resolution but OpenCV seems to always upscale to new resolution

import cv2
import numpy as np
import datetime
import time
import os

cv2.namedWindow("Unregistered Hypercam")
vc = cv2.VideoCapture(0)

vc.set(3, 1920) # Set the horizontal resolution
vc.set(4, 1080) # Set the vertical resolution
vc.set(5, 10)   # Set the framerate

if vc.isOpened():
    rval, frame = vc.read()
else:
    rval = False

lastSave = time.time()

def mfold(name):
    try:  
         os.mkdir(name)
    except OSError:  
         x = 0
    else:  
        print ("Successfully created the directory %s " % fold)

while rval:
    cv2.imshow("Unregistered Hypercam", frame)
    rval, frame = vc.read()
    now = datetime.datetime.now()

    if time.time() > lastSave + 10:
        lastSave = time.time()
        fold = '\\snapshots\\' # This will create folder C:\snapshots
        mfold(fold)
        cv2.imwrite(fold + str(now.year) + '.' + str(now.month) + '.' + str(now.day) + '  ' + str(now.hour) + 'h_' + str(now.minute) + 'm_' + str(now.second) + 's.png', frame)

    key = cv2.waitKey(20)
    if key == 27:
        break

cv2.destroyWindow("Unregistered Hypercam")

Images are blurry and unsharp with black bars and are nowhere similar to images taken with Windows camera app

1 Answers

Here's an example widget to save webcam/streams into video file or screenshot images. It keeps the original resolution of the stream. I used one of my IP camera streams instead of a webcam but it should work the same with a webcam. Currently it opens a stream and saves it as a video but you can modify it to take periodic screenshots. Also to modify the resolution, you can manually resize the frame while keeping aspect ratio with this function (it currently is not used in the widget).

Adjust resolution of frame while maintaining aspect ratio

# Resizes a image and maintains aspect ratio
def maintain_aspect_ratio_resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    # Grab the image size and initialize dimensions
    dim = None
    (h, w) = image.shape[:2]

    # Return original image if no need to resize
    if width is None and height is None:
        return image

    # We are resizing height if width is none
    if width is None:
        # Calculate the ratio of the height and construct the dimensions
        r = height / float(h)
        dim = (int(w * r), height)
    # We are resizing width if height is none
    else:
        # Calculate the ratio of the 0idth and construct the dimensions
        r = width / float(w)
        dim = (width, int(h * r))

    # Return the resized image
    return cv2.resize(image, dim, interpolation=inter)

You can use it like this to adjust width or height

rval, frame = vc.read()

resize_width = maintain_aspect_ratio_resize(frame, width=500)
resize_height = maintain_aspect_ratio_resize(frame, height=500)

Stream and save video widget

from threading import Thread
import cv2

class VideoWriterObject(object):
    def __init__(self, src=0):
        # Create a VideoCapture object
        self.capture = cv2.VideoCapture(src)

        # Default resolutions of the frame are obtained (system dependent)
        self.frame_width = int(self.capture.get(3))
        self.frame_height = int(self.capture.get(4))

        # Set up codec and output video settings
        self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
        self.output_video = cv2.VideoWriter('output.avi', self.codec, 30, (self.frame_width, self.frame_height))

        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()

    def show_frame(self):
        # Display frames in main program
        if self.status:
            cv2.imshow('frame', self.frame)

        # Press Q on keyboard to stop recording
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            self.output_video.release()
            cv2.destroyAllWindows()
            exit(1)

    def save_frame(self):
        # Save obtained frame into video output file
        self.output_video.write(self.frame)

if __name__ == '__main__':
    video_stream_widget = VideoWriterObject(0)
    while True:
        try:
            video_stream_widget.show_frame()
            video_stream_widget.save_frame()
        except AttributeError:
            pass
Related