How to Create The Game Of Tetris using Opencv & Python

In this post, we’ll create the game of Tetris as shown in the video above.


Most readers are probably familiar with Tetris – a popular and addictive video game created by Russian software engineer Alexey Pajitnov in 1984.

Let’s look at the parts of the game and the rules.


The game consists of a board that is 10 cells across and 20 cells high as shown below.

Tetris boardFigure 1 : The Tetris board is a 10 x 20 grid of cells.

Tetris Pieces (a.k.a tetrominoes)

In Tetris, blocks fall from the top of the board vertically down in chunks of 4. The chunks are called tetrominoes but in this post we will simply call them “tetris pieces.”

In Figure 1, we can see a number of Tetris pieces on the bottom of the board (each colored differently), and one blue colored line piece falling down.

There are seven different kinds of pieces. We denote them using the letters “O”, “I”, “S”, “Z”, “L”, “J”, and “T” in our code.

Tetris pieces

Figure 2 : Tetris Pieces

Keyboard Controls

The tetris pieces fall from the top to the bottom of the board.

You can move the pieces by pressing keyboard control keys. In this post, we are using the following keys for controlling the motion of the pieces

  1. Pressing A moves the piece left
  2. D moves the piece right
  3. J rotates piece left
  4. L rotates piece right
  5. I holds the current piece for future use
  6. S moves the piece down by 1 cell. This is also called “soft drop.”
  7. W drops the piece vertically down to the lowest possible cell. It is also called “hard drop.”

Rules of the game

If you make all the cells in one row full by moving and placing the pieces intelligently as they fall, the full line clears and you get points based on how many lines you clear.

If a single line is cleared by an action, you receive 40 points. If two lines are cleared in one shot, you receive 100 points, and if three lines are cleared you get 300 points.

Figure 3: Tetris line clear example. On the left we show four lines are completely full because of the blue block on the right most column. This state changes to the one shown on the right giving the user a TETRIS or 1200 points.

Clearing 4 lines in a single shot gets you 1200 points! This is called a TETRIS and is the highest score you can get in one shot. This is shown in Figure 3.

Your objective is to score as many points as possible before the pile of tetris pieces grows too high.

Creating Tetris using OpenCV and numpy

Let’s see how we can use OpenCV’s drawing functions and keyboard handler along with numpy to create the game of Tetris.

First, we will import some standard libraries.

import cv2
import numpy as np
from random import choice

Now, we will make a board, initialize some other variables, and define the parameter SPEED to be the speed at which the tetris pieces fall.

SPEED = 1 # Controls the speed of the tetris pieces

# Make a board

board = np.uint8(np.zeros([20, 10, 3]))

# Initialize some variables

quit = False
place = False
drop = False
switch = False
held_piece = ""
flag = 0
score = 0

Tetris pieces can have one of seven different shapes.

Seven Kinds of Tetris Pieces

# All the tetris pieces
next_piece = choice(["O", "I", "S", "Z", "L", "J", "T"])

A new Tetris piece always appears in a specific location on the screen.

Next, we will write a function that

  1. Creates a tetris piece
  2. Assigns a color to the piece.

Below we have a function that gets the spawn location and color of a given tetris piece.

def get_info(piece):
    if piece == "I":
        coords = np.array([[0, 3], [0, 4], [0, 5], [0, 6]])
        color = [255, 155, 15]
    elif piece == "T":
        coords = np.array([[1, 3], [1, 4], [1, 5], [0, 4]])
        color = [138, 41, 175]
    elif piece == "L":
        coords = np.array([[1, 3], [1, 4], [1, 5], [0, 5]])
        color = [2, 91, 227]
    elif piece == "J":
        coords = np.array([[1, 3], [1, 4], [1, 5], [0, 3]])
        color = [198, 65, 33]
    elif piece == "S":
        coords = np.array([[1, 5], [1, 4], [0, 3], [0, 4]])
        color = [55, 15, 215]
    elif piece == "Z":
        coords = np.array([[1, 3], [1, 4], [0, 4], [0, 5]])
        color = [1, 177, 89]
        coords = np.array([[0, 4], [0, 5], [1, 4], [1, 5]])
        color = [2, 159, 227]
    return coords, color

Display board

Let’s now write a function for displaying the board and capturing keyboard events.

def display(board, coords, color, next_info, held_info, score, SPEED):
    # Generates the display
    border = np.uint8(127 - np.zeros([20, 1, 3]))
    border_ = np.uint8(127 - np.zeros([1, 34, 3]))
    dummy = board.copy()
    dummy[coords[:,0], coords[:,1]] = color
    right = np.uint8(np.zeros([20, 10, 3]))
    right[next_info[0][:,0] + 2, next_info[0][:,1]] = next_info[1]
    left = np.uint8(np.zeros([20, 10, 3]))
    left[held_info[0][:,0] + 2, held_info[0][:,1]] = held_info[1]
    dummy = np.concatenate((border, left, border, dummy, border, right, border), 1)
    dummy = np.concatenate((border_, dummy, border_), 0)
    dummy = dummy.repeat(20, 0).repeat(20, 1)
    dummy = cv2.putText(dummy, str(score), (520, 200), cv2.FONT_HERSHEY_DUPLEX, 1, [0, 0, 255], 2)
    # Instructions for the player
    dummy = cv2.putText(dummy, "A - move left", (45, 200), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "D - move right", (45, 225), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "S - move down", (45, 250), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "W - hard drop", (45, 275), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "J - rotate left", (45, 300), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "L - rotate right", (45, 325), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    dummy = cv2.putText(dummy, "I - hold", (45, 350), cv2.FONT_HERSHEY_DUPLEX, 0.6, [0, 0, 255])
    cv2.imshow("Tetris", dummy)
    key = cv2.waitKey(int(1000/SPEED))
    return key

Main Loop

This is the main part of the code. We have a while loop where at every iteration we place a new piece in the game.

In Tetris, you can press a certain key to hold a piece. A piece that is held is such a way is available to be used in the future by swapping it with the current piece.

In the code below, we first check if the user wants to swap the current piece with the held piece using the switch variable.

if __name__ == "__main__":
    while not quit:
        # Check if user wants to swap held and current pieces
        if switch:
           # swap held_piece and current_piece
            held_piece, current_piece = current_piece, held_piece
            switch = False

If the switch variable is set to false, we assign the current_piece to the next_piece and randomly choose a new next_piece.

    # Generates the next piece and updates the current piece
    current_piece = next_piece
    next_piece = choice(["I", "T", "L", "J", "Z", "S", "O"])

if flag > 0:
    flag -= 1

Next, we determine the color and position of the current_piece, next_piece, and the held_piece.

# Determines the color and position of the current, next, and held pieces
if held_piece == "":
    held_info = np.array([[0, 0]]), [0, 0, 0]
   held_info = get_info(held_piece)

next_info = get_info(next_piece)

coords, color = get_info(current_piece)
if current_piece == "I":
    top_left = [-2, 3]

This if statement just checks if the game needs to be terminated (i.e., the tetris pieces have stacked too high), and we do this by checking if the next piece’s spawn location doesn’t overlap with another piece.

if not np.all(board[coords[:,0], coords[:,1]] == 0):

Next, we add another while loop inside of the main one. Each iteration of this new loop corresponds to the piece moving down by one block.

First, we show the board using our display() function and receive the keyboard input.

We also make a copy of the original position.

while True:
    # Shows the board and gets the key press
    key = display(board, coords, color, next_info, held_info, score, SPEED)
    # Create a copy of the position
    dummy = coords.copy()

The key variable above stores the ASCII code for the pressed keyboard entry. Depending on which key was pressed, we take different actions.

The a and d keys control the left and right movement of the piece.

if key == ord("a"):
    # Moves the piece left if it isn't against the left wall
    if np.min(coords[:,1]) > 0:
        coords[:,1] -= 1
    if current_piece == "I":
        top_left[1] -= 1
elif key == ord("d"):
    # Moves the piece right if it isn't against the right wall
    if np.max(coords[:,1]) < 9:
        coords[:,1] += 1
        if current_piece == "I":
            top_left[1] += 1

The keys j and l are used to rotate the pieces.

To code rotation, we have three kinds of pieces to deal with – the square piece, the line piece, and all others.

For the square piece, rotating is simple; you don’t do anything!

For anything that’s not a square piece, we can inscribe the piece in a square, which we can rotate.

The line piece is inscribed in a 4×4 square and not a 3×3 square, and therefore we need to treat it differently.

elif key == ord("j") or key == ord("l"):
    # Rotation mechanism
    # arr is the array of nearby points which get rotated and pov is the indexes of the blocks within arr
    if current_piece != "I" and current_piece != "O":
        if coords[1,1] > 0 and coords[1,1] < 9:
            arr = coords[1] - 1 + np.array([[[x, y] for y in range(3)] for x in range(3)])
            pov = coords - coords[1] + 1
    elif current_piece == "I":
        # The straight piece has a 4x4 array, so it needs seperate code
        arr = top_left + np.array([[[x, y] for y in range(4)] for x in range(4)])
        pov = np.array([np.where(np.logical_and(arr[:,:,0] == pos[0], arr[:,:,1] == pos[1])) for pos in coords])
        pov = np.array([k[0] for k in np.swapaxes(pov, 1, 2)])
    # Rotates the array and repositions the piece to where it is now
    if current_piece != "O":
        if key == ord("j"):
            arr = np.rot90(arr, -1)
            arr = np.rot90(arr)
        coords = arr[pov[:,0], pov[:,1]]

Lastly, we will handle the w, i, DELETE, and ESC keys.

Pressing w implements a hard drop. Pressing i holds the piece.

The DELETE and ESC keys end the program.

elif key == ord("w"):
    # Hard drop set to true
    drop = True
elif key == ord("i"):
    # Goes out of the loop and tells the program to switch held and current pieces
    if flag == 0:
        if held_piece == "":
            held_piece = current_piece
            switch = True
        flag = 2
elif key == 8 or key == 27:
    quit = True

We next need to check for collisions with other pieces and prevent the piece from moving into or rotating into another piece.

If such a collision occurs, we change the new position back to the original one using our copy of the coords stored in the dummy variable.

# Checks if the piece is overlapping with other pieces or if it's outside the board, and if so, changes the position to the position before anything happened
if np.max(coords[:,0]) < 20 and np.min(coords[:,0]) >= 0:
    if not (current_piece == "I" and (np.max(coords[:,1]) >= 10 or np.min(coords[:,1]) < 0)):
        if not np.all(board[coords[:,0], coords[:,1]] == 0):
            coords = dummy.copy()
        coords = dummy.copy()
    coords = dummy.copy()

Finally, we code the “hard drop.” We use a while loop to check if the piece can move one step down, and stop moving down if it collides with an existing piece or reaches the bottom of the board.

if drop:
    # Every iteration of the loop moves the piece down by 1 and if the piece is resting on the ground or another piece, then it stops and places it
    while not place:
        if np.max(coords[:,0]) != 19:
            # Checks if the piece is resting on something
            for pos in coords:
                if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
                    place = True
            # If the position of the piece is at the ground level, then it places
            place = True
        if place:
        # Keeps going down and checking when the piece needs to be placed
        coords[:,0] += 1
        score += 1
        if current_piece == "I":
            top_left[0] += 1
    drop = False

If we don’t hard drop, then we just need to check if the piece needs to be placed (i.e. stop moving). A piece is placed when the piece either reaches the bottom of the board or hits another piece.

If none of the above cases apply, we move the piece down by one.

    # Checks if the piece needs to be placed
    if np.max(coords[:,0]) != 19:
        for pos in coords:
            if not np.array_equal(board[pos[0] + 1, pos[1]], [0, 0, 0]):
                place = True
        place = True
if place:
    # Places the piece where it is on the board
    for pos in coords:
        board[tuple(pos)] = color
    # Resets place to False
    place = False

# Moves down by 1

coords[:,0] += 1
if key == ord("s"):
    score += 1
if current_piece == "I":
    top_left[0] += 1

Finally, for each iteration of the outer while loop, (aka each time a piece is placed,) we check if any lines were scored and we update the points.

# Clears lines and also counts how many lines have been cleared and updates the score
lines = 0
for line in range(20):
    if np.all([np.any(pos != 0) for pos in board[line]]):
        lines += 1
        board[1:line+1] = board[:line]
if lines == 1:
    score += 40
elif lines == 2:
    score += 100
elif lines == 3:
    score += 300
elif lines == 4:
    score += 1200


#python #opencv 

What is GEEK

Buddha Community

How to Create The Game Of Tetris using Opencv & Python
Easter  Deckow

Easter Deckow


PyTumblr: A Python Tumblr API v2 Client



Install via pip:

$ pip install pytumblr

Install from source:

$ git clone
$ cd pytumblr
$ python install


Create a client

A pytumblr.TumblrRestClient is the object you'll make all of your calls to the Tumblr API through. Creating one is this easy:

client = pytumblr.TumblrRestClient(
) # Grabs the current user information

Two easy ways to get your credentials to are:

  1. The built-in tool (if you already have a consumer key & secret)
  2. The Tumblr API console at
  3. Get sample login code at

Supported Methods

User Methods # get information about the authenticating user
client.dashboard() # get the dashboard for the authenticating user
client.likes() # get the likes for the authenticating user
client.following() # get the blogs followed by the authenticating user

client.follow('') # follow a blog
client.unfollow('') # unfollow a blog, reblogkey) # like a post
client.unlike(id, reblogkey) # unlike a post

Blog Methods

client.blog_info(blogName) # get information about a blog
client.posts(blogName, **params) # get posts for a blog
client.avatar(blogName) # get the avatar for a blog
client.blog_likes(blogName) # get the likes on a blog
client.followers(blogName) # get the followers of a blog
client.blog_following(blogName) # get the publicly exposed blogs that [blogName] follows
client.queue(blogName) # get the queue for a given blog
client.submission(blogName) # get the submissions for a given blog

Post Methods

Creating posts

PyTumblr lets you create all of the various types that Tumblr supports. When using these types there are a few defaults that are able to be used with any post type.

The default supported types are described below.

  • state - a string, the state of the post. Supported types are published, draft, queue, private
  • tags - a list, a list of strings that you want tagged on the post. eg: ["testing", "magic", "1"]
  • tweet - a string, the string of the customized tweet you want. eg: "Man I love my mega awesome post!"
  • date - a string, the customized GMT that you want
  • format - a string, the format that your post is in. Support types are html or markdown
  • slug - a string, the slug for the url of the post you want

We'll show examples throughout of these default examples while showcasing all the specific post types.

Creating a photo post

Creating a photo post supports a bunch of different options plus the described default options * caption - a string, the user supplied caption * link - a string, the "click-through" url for the photo * source - a string, the url for the photo you want to use (use this or the data parameter) * data - a list or string, a list of filepaths or a single file path for multipart file upload

#Creates a photo post using a source URL
client.create_photo(blogName, state="published", tags=["testing", "ok"],

#Creates a photo post using a local filepath
client.create_photo(blogName, state="queue", tags=["testing", "ok"],
                    tweet="Woah this is an incredible sweet post [URL]",

#Creates a photoset post using several local filepaths
client.create_photo(blogName, state="draft", tags=["jb is cool"], format="markdown",
                    data=["/Users/johnb/path/to/my/image.jpg", "/Users/johnb/Pictures/kittens.jpg"],
                    caption="## Mega sweet kittens")

Creating a text post

Creating a text post supports the same options as default and just a two other parameters * title - a string, the optional title for the post. Supports markdown or html * body - a string, the body of the of the post. Supports markdown or html

#Creating a text post
client.create_text(blogName, state="published", slug="testing-text-posts", title="Testing", body="testing1 2 3 4")

Creating a quote post

Creating a quote post supports the same options as default and two other parameter * quote - a string, the full text of the qote. Supports markdown or html * source - a string, the cited source. HTML supported

#Creating a quote post
client.create_quote(blogName, state="queue", quote="I am the Walrus", source="Ringo")

Creating a link post

  • title - a string, the title of post that you want. Supports HTML entities.
  • url - a string, the url that you want to create a link post for.
  • description - a string, the desciption of the link that you have
#Create a link post
client.create_link(blogName, title="I like to search things, you should too.", url="",
                   description="Search is pretty cool when a duck does it.")

Creating a chat post

Creating a chat post supports the same options as default and two other parameters * title - a string, the title of the chat post * conversation - a string, the text of the conversation/chat, with diablog labels (no html)

#Create a chat post
chat = """John: Testing can be fun!
Renee: Testing is tedious and so are you.
John: Aw.
client.create_chat(blogName, title="Renee just doesn't understand.", conversation=chat, tags=["renee", "testing"])

Creating an audio post

Creating an audio post allows for all default options and a has 3 other parameters. The only thing to keep in mind while dealing with audio posts is to make sure that you use the external_url parameter or data. You cannot use both at the same time. * caption - a string, the caption for your post * external_url - a string, the url of the site that hosts the audio file * data - a string, the filepath of the audio file you want to upload to Tumblr

#Creating an audio file
client.create_audio(blogName, caption="Rock out.", data="/Users/johnb/Music/my/new/sweet/album.mp3")

#lets use soundcloud!
client.create_audio(blogName, caption="Mega rock out.", external_url="")

Creating a video post

Creating a video post allows for all default options and has three other options. Like the other post types, it has some restrictions. You cannot use the embed and data parameters at the same time. * caption - a string, the caption for your post * embed - a string, the HTML embed code for the video * data - a string, the path of the file you want to upload

#Creating an upload from YouTube
client.create_video(blogName, caption="Jon Snow. Mega ridiculous sword.",

#Creating a video post from local file
client.create_video(blogName, caption="testing", data="/Users/johnb/testing/ok/")

Editing a post

Updating a post requires you knowing what type a post you're updating. You'll be able to supply to the post any of the options given above for updates.

client.edit_post(blogName, id=post_id, type="text", title="Updated")
client.edit_post(blogName, id=post_id, type="photo", data="/Users/johnb/mega/awesome.jpg")

Reblogging a Post

Reblogging a post just requires knowing the post id and the reblog key, which is supplied in the JSON of any post object.

client.reblog(blogName, id=125356, reblog_key="reblog_key")

Deleting a post

Deleting just requires that you own the post and have the post id

client.delete_post(blogName, 123456) # Deletes your post :(

A note on tags: When passing tags, as params, please pass them as a list (not a comma-separated string):

client.create_text(blogName, tags=['hello', 'world'], ...)

Getting notes for a post

In order to get the notes for a post, you need to have the post id and the blog that it is on.

data = client.notes(blogName, id='123456')

The results include a timestamp you can use to make future calls.

data = client.notes(blogName, id='123456', before_timestamp=data["_links"]["next"]["query_params"]["before_timestamp"])

Tagged Methods

# get posts with a given tag
client.tagged(tag, **params)

Using the interactive console

This client comes with a nice interactive console to run you through the OAuth process, grab your tokens (and store them for future use).

You'll need pyyaml installed to run it, but then it's just:

$ python

and away you go! Tokens are stored in ~/.tumblr and are also shared by other Tumblr API clients like the Ruby client.

Running tests

The tests (and coverage reports) are run with nose, like this:

python test

Author: tumblr
Source Code:
License: Apache-2.0 license

#python #api 

Verda  Conroy

Verda Conroy


Create a Virtual Pen and Eraser with Python OpenCV - Genial Code

Learn Free how to create a virtual pen and eraser with python and OpenCV with source code and complete guide. This entire application is built fundamentally on contour detection. It can be thought of as something like closed color curves on compromises that have the same color or intensity, it’s like a blob. In this project we use color masking to get the binary mask of our target color pen, then we use the counter detection to find the location of this pen and the contour to find it.

#python #create virtual pen and eraser with opencv #create virtual pen and eraser with python opencv #programming #opencv #python opencv

Ray  Patel

Ray Patel


Lambda, Map, Filter functions in python

Welcome to my Blog, In this article, we will learn python lambda function, Map function, and filter function.

Lambda function in python: Lambda is a one line anonymous function and lambda takes any number of arguments but can only have one expression and python lambda syntax is

Syntax: x = lambda arguments : expression

Now i will show you some python lambda function examples:

#python #anonymous function python #filter function in python #lambda #lambda python 3 #map python #python filter #python filter lambda #python lambda #python lambda examples #python map

Shardul Bhatt

Shardul Bhatt


Why use Python for Software Development

No programming language is pretty much as diverse as Python. It enables building cutting edge applications effortlessly. Developers are as yet investigating the full capability of end-to-end Python development services in various areas. 

By areas, we mean FinTech, HealthTech, InsureTech, Cybersecurity, and that's just the beginning. These are New Economy areas, and Python has the ability to serve every one of them. The vast majority of them require massive computational abilities. Python's code is dynamic and powerful - equipped for taking care of the heavy traffic and substantial algorithmic capacities. 

Programming advancement is multidimensional today. Endeavor programming requires an intelligent application with AI and ML capacities. Shopper based applications require information examination to convey a superior client experience. Netflix, Trello, and Amazon are genuine instances of such applications. Python assists with building them effortlessly. 

5 Reasons to Utilize Python for Programming Web Apps 

Python can do such numerous things that developers can't discover enough reasons to admire it. Python application development isn't restricted to web and enterprise applications. It is exceptionally adaptable and superb for a wide range of uses.

Robust frameworks 

Python is known for its tools and frameworks. There's a structure for everything. Django is helpful for building web applications, venture applications, logical applications, and mathematical processing. Flask is another web improvement framework with no conditions. 

Web2Py, CherryPy, and Falcon offer incredible capabilities to customize Python development services. A large portion of them are open-source frameworks that allow quick turn of events. 

Simple to read and compose 

Python has an improved sentence structure - one that is like the English language. New engineers for Python can undoubtedly understand where they stand in the development process. The simplicity of composing allows quick application building. 

The motivation behind building Python, as said by its maker Guido Van Rossum, was to empower even beginner engineers to comprehend the programming language. The simple coding likewise permits developers to roll out speedy improvements without getting confused by pointless subtleties. 

Utilized by the best 

Alright - Python isn't simply one more programming language. It should have something, which is the reason the business giants use it. Furthermore, that too for different purposes. Developers at Google use Python to assemble framework organization systems, parallel information pusher, code audit, testing and QA, and substantially more. Netflix utilizes Python web development services for its recommendation algorithm and media player. 

Massive community support 

Python has a steadily developing community that offers enormous help. From amateurs to specialists, there's everybody. There are a lot of instructional exercises, documentation, and guides accessible for Python web development solutions. 

Today, numerous universities start with Python, adding to the quantity of individuals in the community. Frequently, Python designers team up on various tasks and help each other with algorithmic, utilitarian, and application critical thinking. 

Progressive applications 

Python is the greatest supporter of data science, Machine Learning, and Artificial Intelligence at any enterprise software development company. Its utilization cases in cutting edge applications are the most compelling motivation for its prosperity. Python is the second most well known tool after R for data analytics.

The simplicity of getting sorted out, overseeing, and visualizing information through unique libraries makes it ideal for data based applications. TensorFlow for neural networks and OpenCV for computer vision are two of Python's most well known use cases for Machine learning applications.


Thinking about the advances in programming and innovation, Python is a YES for an assorted scope of utilizations. Game development, web application development services, GUI advancement, ML and AI improvement, Enterprise and customer applications - every one of them uses Python to its full potential. 

The disadvantages of Python web improvement arrangements are regularly disregarded by developers and organizations because of the advantages it gives. They focus on quality over speed and performance over blunders. That is the reason it's a good idea to utilize Python for building the applications of the future.

#python development services #python development company #python app development #python development #python in web development #python software development

HI Python

HI Python


Video Chat App Python: How to Create a Video Chat App Using Python and OpenCV

Video Chat App in Python Using OpenCV and Networking

In this article, I am going to show you,_ how to Create a Video Chat App Using Python OpenCV and Socket Programming__ with__ an easy step-by-step tutorial._

Table of Content:

**· **Introduction and Information to Technologies Used Here

**· **Prerequisite:

**· **Python Code for Video Chat Application:

**∘ ** file

**∘ ** file

**· **Conclusion:

**· **Github Project Link

Introduction to Technologies Used Here:

  1. Python OpenCV
  2. Socket Programming in Python

#opencv #networking #python #python and opencv #how to create a video chat app #video chat app python