{"id":21701574,"url":"https://github.com/harimkang/opencv-with-zoom","last_synced_at":"2025-04-12T13:42:54.068Z","repository":{"id":37446385,"uuid":"230612929","full_name":"harimkang/openCV-with-Zoom","owner":"harimkang","description":" This code adds camera streaming, zooming, image capturing, and video recording using openCV.","archived":false,"fork":false,"pushed_at":"2020-07-27T06:08:23.000Z","size":976,"stargazers_count":35,"open_issues_count":0,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-26T08:22:59.475Z","etag":null,"topics":["korean","opencv","opencv-python","streaming","touch-event","touch-zoom","ui","zoom","zoom-functions"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/harimkang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-28T13:21:35.000Z","updated_at":"2024-12-25T11:07:27.000Z","dependencies_parsed_at":"2022-08-19T18:30:31.988Z","dependency_job_id":null,"html_url":"https://github.com/harimkang/openCV-with-Zoom","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harimkang%2FopenCV-with-Zoom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harimkang%2FopenCV-with-Zoom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harimkang%2FopenCV-with-Zoom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harimkang%2FopenCV-with-Zoom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harimkang","download_url":"https://codeload.github.com/harimkang/openCV-with-Zoom/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248574658,"owners_count":21127049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["korean","opencv","opencv-python","streaming","touch-event","touch-zoom","ui","zoom","zoom-functions"],"created_at":"2024-11-25T20:24:19.807Z","updated_at":"2025-04-12T13:42:54.047Z","avatar_url":"https://github.com/harimkang.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# opencv-with-zoom\n![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fharimkang/openCV-with-Zoom) ![License](https://img.shields.io/github/license/harimkang/opencv-with-zoom?style=plastic) ![Stars](https://img.shields.io/github/stars/harimkang/opencv-with-zoom?style=social)\n\n\n![love and jo](https://user-images.githubusercontent.com/38045080/88261899-1d189380-cd02-11ea-9058-740b2f6a48b4.png)\n\n## Blog for Korean\n\nThe READ ME contents in Korean can be found at the address below.\n\n\u003chttps://davinci-ai.tistory.com/8\u003e\n\n## Environment\n\n- Python3\n- opencv-python\n\n## Installation\n\nInstall the dependency.\n```sh\n$ pip install opencv-python\n```\n\nClone Repository...\n\n```sh\n$ mkdir project\n$ cd project\n$ git clone https://github.com/harimkang/opencv-with-zoom.git\n$ cd opencv-with-zoom\n```\n\n## Start\n\n```sh\n$ python Camera.py\n```\nAnd you can zoom through the double click.\n\nYou can exit through the q button.\n\n\n## Goal\n\nThe repository will bring the camera's screen through openCV to show it, add zoom-in and zoom-out functions, and write code to use the zoom function using screen touch events. These codes are written in python code.\n\n![opencv%20with%20zoom/Untitled.png](opencv%20with%20zoom/Untitled.png)\n\nThe part related to the function of the repository in the Activity Diagram is as shown above.\n\n## Create openCV streaming screen\n\nFirst of all, write code to show the live streaming screen using openCV.\n```python\nimport cv2\nclass Camera:\n    def __init__(self, mirror=False):\n        self.data = None\n        self.cam = cv2.VideoCapture(0)\n\n        self.WIDTH = 640\n        self.HEIGHT = 480\n\n        self.center_x = self.WIDTH / 2\n        self.center_y = self.HEIGHT / 2\n        self.touched_zoom = False\n\n        self.scale = 1\n        self.__setup()\n\n        self.recording = False\n\n        self.mirror = mirror\n\n    def __setup(self):\n        self.cam.set(cv2.CAP_PROP_FRAME_WIDTH, self.WIDTH)\n        self.cam.set(cv2.CAP_PROP_FRAME_HEIGHT, self.HEIGHT)\n        time.sleep(2)\n\n    def stream(self):\n        # streaming thread function\n        def streaming():\n            # The actual threaded function\n            self.ret = True\n            while self.ret:\n                self.ret, np_image = self.cam.read()\n                if np_image is None:\n                    continue\n                if self.mirror:\n                    # Inverted left and right in mirror mode\n                    np_image = cv2.flip(np_image, 1)\n                self.data = np_image\n                k = cv2.waitKey(1)\n                if k == ord('q'):\n                    self.release()\n                    break\n\n        Thread(target=streaming).start()\n\n    def show(self):\n        while True:\n            frame = self.data\n            if frame is not None:\n                cv2.imshow('Davinci AI', frame)\n            key = cv2.waitKey(1)\n            if key == ord('q'):\n                # q : close\n                self.release()\n                cv2.destroyAllWindows()\n                break\n\n    def release(self):\n        self.cam.release()\n        cv2.destroyAllWindows()\n\n\nif __name__ == '__main__':\n    cam = Camera(mirror=True)\n    cam.stream()\n    cam.show()\n```\n\nI wrote Camera class that sends streaming screen of personal camera through methods provided in openCV. When you run the code, it simply displays the video from the camera connected to your computer.\n\nI want to add basic zooming, zooming through touch events.\n\n## Adding basic zoom features\n\nFirst of all, before we start writing the code, let's easily represent it with a picture. Since we are going to implement zoom function through touch event, we wrote this in consideration.\n\nThe circle means the touched position, and it looks at the size of the top and bottom and sides based on the position and considers the small part as half of the new frame to find and cut the frame of the new size.\n\n![opencv%20with%20zoom/Untitled%201.png](opencv%20with%20zoom/Untitled%201.png)\n\nNow let's write the code that handles the basic zoom functions. I know that openCV doesn't provide a zoom-related method, so I wrote a code that cuts and resizes the screen to fit a variable that is a multiple of scale.\n```python\n    def __zoom(self, img, center=None):\n            # actual function to zoom\n            height, width = img.shape[:2]\n            if center is None:\n                #   Calculation when the center value is the initial value\n                center_x = int(width / 2)\n                center_y = int(height / 2)\n                radius_x, radius_y = int(width / 2), int(height / 2)\n            else:\n                #   Calculation at a specific location\n                center_x, center_y = center\n    \n                center_x, center_y = int(center_x), int(center_y)\n                left_x, right_x = center_x, int(width - center_x)\n                up_y, down_y = int(height - center_y), center_y\n                radius_x = min(left_x, right_x)\n                radius_y = min(up_y, down_y)\n    \n            # Actual zoom code\n            radius_x, radius_y = int(self.scale * radius_x), int(self.scale * radius_y)\n    \n            # size calculation\n            min_x, max_x = center_x - radius_x, center_x + radius_x\n            min_y, max_y = center_y - radius_y, center_y + radius_y\n    \n            # Crop image to size\n            cropped = img[min_y:max_y, min_x:max_x]\n            # Return to original size\n            new_cropped = cv2.resize(cropped, (width, height))\n    \n            return new_cropped\n```\nThe code is divided into two types when the center touched and the zoom function is used. It takes the size of the image, finds the center value, calculates the size according to the scale, crops it accordingly, and increases the size to the original size to return.\n\n```python\ndef touch_init(self):\n    self.center_x = self.WIDTH / 2\n    self.center_y = self.HEIGHT / 2\n    self.touched_zoom = False\n    self.scale = 1\n        \ndef zoom_out(self):\n    # scale 값을 조정하여 zoom-out\n    if self.scale \u003c 1:\n        self.scale += 0.1\n    if self.scale == 1:\n        self.center_x = self.WIDTH\n        self.center_y = self.HEIGHT\n        self.touched_zoom = False\n    \ndef zoom_in(self):\n    # scale 값을 조정하여 zoom-in\n    if self.scale \u003e 0.2:\n        self.scale -= 0.1\n\ndef zoom(self, num):\n    if num == 0:\n        self.zoom_in()\n    elif num == 1:\n        self.zoom_out()\n    elif num == 2:\n        self.touch_init()\n```\n\nThe zoom in and out functions are structured to function by adjusting the scale value.\n```python\nif self.touched_zoom:\n    np_image = self.__zoom(np_image, (self.center_x, self.center_y))\nelse:\n    if not self.scale == 1:\n        np_image = self.__zoom(np_image)\n```\nPut the above code before the middle of the stream method (self.data = np_image) to check whether the zoom by touch function is already executed or the basic zoom function is executed.\n\n## Adding zoom function by Touch-Event\n```python\ndef show(self):\n    while True:\n        frame = self.data\n        if frame is not None:\n            cv2.imshow('Davinci AI', frame)\n            cv2.setMouseCallback('Davinci AI', self.mouse_callback)\n        key = cv2.waitKey(1)\n        if key == ord('q'):\n            # q : close\n            self.release()\n            cv2.destroyAllWindows()\n            break\ndef mouse_callback(self, event, x, y, flag, param):\n    if event == cv2.EVENT_LBUTTONDBLCLK:\n        self.get_location(x, y)\n        self.zoom_in()\n    elif event == cv2.EVENT_RBUTTONDOWN:\n        self.zoom_out()\n```\n\nIn the code above, I added the red background cv2.setMouseCallback ('Davinci AI', self.mouse_callback) to the show function. That code means you assign a function called self.mouse_callback to a function that handles touch events on the screen.\n\nThe following mouse_callback function is a function that handles touch events. The code is configured to be zoom_in when double-clicking the left mouse and zoom_out when double-clicking the right mouse.\n\n![opencv%20with%20zoom/Untitled%202.png](opencv%20with%20zoom/Untitled%202.png)\n\n### Problem occurred!\n\nTouch zoom at the edges tends to distort the screen or to zoom in too suddenly, so we want to fix it so that it's proportional to touch zoom.\n\nAs shown in the figure below, during touch event of the edge part, the touch position is adjusted according to a certain ratio to prevent distortion. Enable magnification while maintaining a reasonable ratio.\n\n![opencv%20with%20zoom/Untitled%203.png](opencv%20with%20zoom/Untitled%203.png)\n\nThe code above is shown below.\n```python\ndef __zoom(self, img, center=None):\n    # actual function to zoom\n    height, width = img.shape[:2]\n    if center is None:\n        #   Calculation when the center value is the initial value\n        center_x = int(width / 2)\n        center_y = int(height / 2)\n        radius_x, radius_y = int(width / 2), int(height / 2)\n    else:\n        #   Calculation at a specific location\n        rate = height / width\n        center_x, center_y = center\n\n    #   Calculate centroids for ratio range\n    if center_x \u003c width * (1-rate):\n        center_x = width * (1-rate)\n    elif center_x \u003e width * rate:\n        center_x = width * rate\n    if center_y \u003c height * (1-rate):\n        center_y = height * (1-rate)\n    elif center_y \u003e height * rate:\n        center_y = height * rate\n\n    center_x, center_y = int(center_x), int(center_y)\n    left_x, right_x = center_x, int(width - center_x)\n    up_y, down_y = int(height - center_y), center_y\n    radius_x = min(left_x, right_x)\n    radius_y = min(up_y, down_y)\n\n    # Actual zoom code\n    radius_x, radius_y = int(self.scale * radius_x), int(self.scale * radius_y)\n\n    # size calculation\n    min_x, max_x = center_x - radius_x, center_x + radius_x\n    min_y, max_y = center_y - radius_y, center_y + radius_y\n\n    # Crop image to size\n    cropped = img[min_y:max_y, min_x:max_x]\n    # Return to original size\n    new_cropped = cv2.resize(cropped, (width, height))\n\n    return new_cropped\n```\nAdded a red background code to the __zoom function responsible for the zoom function.\n\n![opencv%20with%20zoom/Untitled%204.png](opencv%20with%20zoom/Untitled%204.png)\n\n## Additional features\n\n\nIn addition, we want to add a function to capture and save the current image and to record a video.\n```python\ndef save_picture(self):\n    # Function to save image\n    ret, img = self.cam.read()\n    if ret:\n        now = datetime.datetime.now()\n        date = now.strftime('%Y%m%d')\n        hour = now.strftime('%H%M%S')\n        user_id = '00001'\n        filename = './images/cvui_{}_{}_{}.png'.format(date, hour, user_id)\n        cv2.imwrite(filename, img)\n        self.image_queue.put_nowait(filename)\n```\nFirst is the image capture function. You need to create a folder called images first.\n```python\ndef record_video(self):\n    # Video recording function\n    fc = 20.0\n    record_start_time = time.time()\n    now = datetime.datetime.now()\n    date = now.strftime('%Y%m%d')\n    t = now.strftime('%H')\n    num = 1\n    filename = 'videos/cvui_{}_{}_{}.avi'.format(date, t, num)\n    while os.path.exists(filename):\n        num += 1\n        filename = 'videos/cvui_{}_{}_{}.avi'.format(date, t, num)\n    codec = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')\n    out = cv2.VideoWriter(filename, codec, fc, (int(self.cam.get(3)), int(self.cam.get(4))))\n    while self.recording:\n        if time.time() - record_start_time \u003e= 600:\n            self.record_video()\n            break\n        ret, frame = self.cam.read()\n                    if ret:\n            if len(os.listdir('./videos')) \u003e= 100:\n                name = self.video_queue.get()\n                if os.path.exists(name):\n                    os.remove(name)\n            out.write(frame)\n            self.video_queue.put_nowait(filename)\n        k = cv2.waitKey(1)\n        if k == ord('q'):\n            break\n```\nNext is the video recording function. The code is configured to be saved as another file when recording for more than 10 minutes. It also queues to delete over 100 files. (Method to adjust file size not too big)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharimkang%2Fopencv-with-zoom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharimkang%2Fopencv-with-zoom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharimkang%2Fopencv-with-zoom/lists"}