OpenCV & Python - Image too big to display - python

I have an image that is 6400 × 3200, while my screen is 1280 x 800. Therefore, the image needs to be resized for display only. I am using Python and OpenCV 2.4.9.
According to OpenCV Documentation,
If you need to show an image that is bigger than the screen resolution, you will need to call namedWindow("", WINDOW_NORMAL) before the imshow.
That is what I am doing, but the image is not fitted to the screen, only a portion is shown because it's too big. I've also tried with cv2.resizeWindow, but it doesn't make any difference.
import cv2
cv2.namedWindow("output", cv2.WINDOW_NORMAL) # Create window with freedom of dimensions
# cv2.resizeWindow("output", 400, 300) # Resize window to specified dimensions
im = cv2.imread("earth.jpg") # Read image
cv2.imshow("output", im) # Show image
cv2.waitKey(0) # Display the image infinitely until any keypress

Although I was expecting an automatic solution (fitting to the screen automatically), resizing solves the problem as well.
import cv2
cv2.namedWindow("output", cv2.WINDOW_NORMAL) # Create window with freedom of dimensions
im = cv2.imread("earth.jpg") # Read image
imS = cv2.resize(im, (960, 540)) # Resize image
cv2.imshow("output", imS) # Show image
cv2.waitKey(0) # Display the image infinitely until any keypress

The other answers perform a fixed (width, height) resize. If you wanted to resize to a specific size while maintaining aspect ratio, use this
def ResizeWithAspectRatio(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
else:
r = width / float(w)
dim = (width, int(h * r))
return cv2.resize(image, dim, interpolation=inter)
Example
image = cv2.imread('img.png')
resize = ResizeWithAspectRatio(image, width=1280) # Resize by width OR
# resize = ResizeWithAspectRatio(image, height=1280) # Resize by height
cv2.imshow('resize', resize)
cv2.waitKey()

Use this for example:
cv2.namedWindow('finalImg', cv2.WINDOW_NORMAL)
cv2.imshow("finalImg",finalImg)

The only way resizeWindow worked for me was to have it after imshow. This is the order I'm using:
# Create a Named Window
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
# Move it to (X,Y)
cv2.moveWindow(win_name, X, Y)
# Show the Image in the Window
cv2.imshow(win_name, image)
# Resize the Window
cv2.resizeWindow(win_name, width, height)
# Wait for <> miliseconds
cv2.waitKey(wait_time)

In OpenCV, cv2.namedWindow() just creates a window object, but doesn't resize the original image. You can use cv2.resize(img, resolution) to solve the problem.
Here's what it displays, a 740 * 411 resolution image.
image = cv2.imread("740*411.jpg")
cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Here, it displays a 100 * 200 resolution image after resizing. Remember the resolution parameter use column first then is row.
image = cv2.imread("740*411.jpg")
image = cv2.resize(image, (200, 100))
cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

This code will resize the image so that it can retain it's aspect ratio and only ever take up a specified fraction of the screen area.
It will automatically adjust depending on your screen size and the size of the image.
Use the area variable to change the max screen area you want the image to be able to take up. The example shows it displayed at quarter the screen size.
import cv2
import tkinter as tk
from math import *
img = cv2.imread("test.jpg")
area = 0.25
h, w = img.shape[:2]
root = tk.Tk()
screen_h = root.winfo_screenheight()
screen_w = root.winfo_screenwidth()
vector = sqrt(area)
window_h = screen_h * vector
window_w = screen_w * vector
if h > window_h or w > window_w:
if h / window_h >= w / window_w:
multiplier = window_h / h
else:
multiplier = window_w / w
img = cv2.resize(img, (0, 0), fx=multiplier, fy=multiplier)
cv2.imshow("output", img)
cv2.waitKey(0)
I've also made a similar function where area is still a parameter but so is window height and window width.
If no area is input then it will use a defined height and width (window_h, window_w) of the window size you would like the image to fit inside.
If an input is given for all parameters then 'area' is prioritised.
import cv2
import tkinter as tk
from math import *
def resize_image(img, area=0.0, window_h=0, window_w=0):
h, w = img.shape[:2]
root = tk.Tk()
screen_h = root.winfo_screenheight()
screen_w = root.winfo_screenwidth()
if area != 0.0:
vector = math.sqrt(area)
window_h = screen_h * vector
window_w = screen_w * vector
if h > window_h or w > window_w:
if h / window_h >= w / window_w:
multiplier = window_h / h
else:
multiplier = window_w / w
img = cv2.resize(img, (0, 0), fx=multiplier, fy=multiplier)
return img
# using area
initial_image = cv2.imread("test.jpg")
resized_image = resize_image(initial_image, area=0.25))
cv2.imshow("output", resized_image)
cv2.waitKey(0)
# using window height and width
initial_image = cv2.imread("test.jpg")
resized_image = resize_image(initial_image, window_h = 480, window_w = 270))
cv2.imshow("output", resized_image)
cv2.waitKey(0)

Looks like opencv lib is pretty sensitive to parameters passed to the methods. The following code worked for me using opencv 4.3.0:
win_name = "visualization" # 1. use var to specify window name everywhere
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL) # 2. use 'normal' flag
img = cv2.imread(filename)
h,w = img.shape[:2] # suits for image containing any amount of channels
h = int(h / resize_factor) # one must compute beforehand
w = int(w / resize_factor) # and convert to INT
cv2.resizeWindow(win_name, w, h) # use variables defined/computed BEFOREHAND
cv2.imshow(win_name, img)

Try this:
image = cv2.imread("img/Demo.jpg")
image = cv2.resize(image,(240,240))
The image is now resized. Displaying it will render in 240x240.

The cv2.WINDOW_NORMAL option works correctly but the first time it displays the window in an standard size.
If you resize the window like any other windows in your computer, by position the mouse over the edge of the window you want to resize and then drag the mouse to the position you want. If you do this to both width and height of the window to the size you want to obtain.
The following times you refresh the window, by executing the code, OpenCV will generate the window with the size of the last time it was shown or modified.

Try this code:
img = cv2.imread("Fab2_0.1 X 1.03MM GRID.jpg", cv2.IMREAD_GRAYSCALE)
image_scale_down = 3
x = (int)(img.shape[0]/image_scale_down)
y = (int)(img.shape[1]/image_scale_down)
image = cv2.resize(img, (x,y))
cv2.imshow("image_title", image)
cv2.waitKey(5000)
cv2.destroyAllWindows()

The most upvote answer is perfect !
I just add my code for those who want some "dynamic" resize handling depending of the ratio.
import cv2
from win32api import GetSystemMetrics
def get_resized_for_display_img(img):
screen_w, screen_h = GetSystemMetrics(0), GetSystemMetrics(1)
print("screen size",screen_w, screen_h)
h,w,channel_nbr = img.shape
# img get w of screen and adapt h
h = h * (screen_w / w)
w = screen_w
if h > screen_h: #if img h still too big
# img get h of screen and adapt w
w = w * (screen_h / h)
h = screen_h
w, h = w*0.9, h*0.9 # because you don't want it to be that big, right ?
w, h = int(w), int(h) # you need int for the cv2.resize
return cv2.resize(img, (w, h))

Try this code
img = cv2.resize(img,(1280,800))

Try with this code:
from PIL import Image
Image.fromarray(image).show()

Related

Merging a transparent image to another background

I have 2 images as below, both are in RGBA format
I want to overlay the object into a fixed region in the background. However, my codes produces a weird result:
Can someone have a look at my code to see where I was wrong. Thanks in advance
import numpy as np
import matplotlib.pyplot as plt
import cv2
import glob
from PIL import Image
bg = np.array(Image.open('background.png'))
obj = np.array(Image.open('object.png'))
#RESIZE BACKGROUND
scale_percent = 50 # percent of original size
width = int(bg.shape[1] * scale_percent / 100)
height = int(bg.shape[0] * scale_percent / 100)
dim = (width, height)
bg = resized = cv2.resize(bg, dim, interpolation = cv2.INTER_AREA)
#RESIZE OBJECT
scale_percent = 80 # percent of original size
width = int(obj.shape[1] * scale_percent / 100)
height = int(obj.shape[0] * scale_percent / 100)
dim = (width, height)
# resize image
obj = resized = cv2.resize(obj, dim, interpolation=cv2.INTER_AREA)
#create ROI
rows, cols, channels = obj.shape
bg_rows, bg_cols, bg_channels = bg.shape
roi = bg[bg_rows-rows:bg_rows:, bg_cols-cols:bg_cols:]
img2gray = cv2.cvtColor(obj, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
img2_fg = cv2.bitwise_and(obj, obj, mask=mask)
dst = cv2.add(img1_bg, img2_fg)
bg[bg_rows-rows:bg_rows:, bg_cols-cols:bg_cols:] = dst
Image.fromarray(bg)
You should use ImageDraw() function from the pillow library. It will solve your problem by giving the mode same as the 2nd image.

How to save image with resolution greater than 1080p?

I'm trying to use Logitech BRIO in 3840x2160 resolution, when I execute the python code, a window opens with the camera image (in 3840x2160), but when I save a frame, the program creates a image in 1920x1080. How can I save the image in 4k
high resolution?
I'm using opencv-python==4.1.0.25
import cv2
import time
def main(args):
CAMERA_PORT = 0
IMAGEWIDTH = 3840
IMAGEHEIGHT = 2160
#Propriedades de configuracao da camera
# 3 = width da camera, 4 = height da camera
CAMERA_PROP_WIDTH = 3
CAMERA_PROP_HEIGHT = 4
camera = cv2.VideoCapture(CAMERA_PORT)
camera.set(CAMERA_PROP_WIDTH, IMAGEWIDTH)
camera.set(CAMERA_PROP_HEIGHT, IMAGEHEIGHT)
imagePath = "/home/barbosa/Documents/camera-controller/images/image.png"
while(True):
retval, image = camera.read()
cv2.imshow('Foto',image)
k = cv2.waitKey(100)
if k == 27:
break
elif k == ord('s'):
cv2.imwrite(imagePath,image)
break
cv2.destroyAllWindows()
camera.release()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
You can make your own custom resize function to upscale and maintain aspect ratio then save the image. I tested it on my IP camera instead of a webcam.
Here's the resize function
# 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)
Full code
import cv2
import time
# 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)
def main(args):
CAMERA_PORT = 0
IMAGEWIDTH = 3840
IMAGEHEIGHT = 2160
#Propriedades de configuracao da camera
# 3 = width da camera, 4 = height da camera
CAMERA_PROP_WIDTH = 3
CAMERA_PROP_HEIGHT = 4
camera = cv2.VideoCapture(CAMERA_PORT)
camera.set(CAMERA_PROP_WIDTH, IMAGEWIDTH)
camera.set(CAMERA_PROP_HEIGHT, IMAGEHEIGHT)
imagePath = "/home/barbosa/Documents/camera-controller/images/image.png"
while(True):
retval, image = camera.read()
cv2.imshow('Foto',image)
k = cv2.waitKey(100)
if k == 27:
break
elif k == ord('s'):
image = maintain_aspect_ratio_resize(image, width=IMAGEWIDTH)
cv2.imwrite(imagePath,image)
break
cv2.destroyAllWindows()
camera.release()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))

How can i create frame with python that i can put a picture into frame

I want to put my pic in my frame.I used this cod :
from PIL import Image
img = Image.open('Pic.jpg')
frame = Image.open('Frame.jpg')
size1 = 354,362
paste_point = 69,339
Pic = img.resize((size1))
frame.paste(img, (paste_point))
frame.show()
When i run the program, my pic doesn't put in my frame.
How can i create a frame in python
your question solution depends always on your pic size and frame size ,so code must be adjusted according to pixel size of your pic
i am giving generic code for your problem maynot fit to your image standards
from PIL import Image
img = Image.open('Pic.jpg')
img_w, img_h = img.size
frame = Image.new('RGBA', (1440, 900), (255, 255, 255, 255))
bg_w, bg_h = frame.size
offset = ((bg_w - img_w) / 2, (bg_h - img_h) / 2)
frame.paste(img, offset)
frame.save('out.png')

Python: Image resizing: keep proportion - add white background

I would like to create a Python script to resize images, but not changing its proportions, just by adding a white background
(So, a : 500*700 px image would transform to a 700*700 px image by adding 100 px of a white band on each side)
The three image types I use are .PNG, .JPG and .GIF. I am not even sure it is possible for Gifs, PNG and JPG would already be awesome.
In my case, they have to be squares. But if any of you manage to do it for adaptable to any proportion, it would benefit the maximum number of people that see this thread and you would be even more awesome !
I saw same threads for other languages but not python, do you guys know how you do this ?
PS : I am using Python 3
What I tried :
Combining 3 images together.
If we take our 500*700 px image :
Creating two white images of 100*700px and put one on each side of the image. Inspired by :
Combine several images horizontally with Python
But, I am kind of new on python, and I haven't succeded.
Finally did it :
def Reformat_Image(ImageFilePath):
from PIL import Image
image = Image.open(ImageFilePath, 'r')
image_size = image.size
width = image_size[0]
height = image_size[1]
if(width != height):
bigside = width if width > height else height
background = Image.new('RGBA', (bigside, bigside), (255, 255, 255, 255))
offset = (int(round(((bigside - width) / 2), 0)), int(round(((bigside - height) / 2),0)))
background.paste(image, offset)
background.save('out.png')
print("Image has been resized !")
else:
print("Image is already a square, it has not been resized !")
Thanks to #Blotosmetek for the suggestion, pasting a centered image is definitely simpler than creating images and combining them !
PS : If you don't have PIL yet, the library's name to install it with pip is "pillow", not PIL. But still, you use it as PIL in the code.
Thanks #Jay D., here a bit more general version:
from PIL import Image
def resize(image_pil, width, height):
'''
Resize PIL image keeping ratio and using white background.
'''
ratio_w = width / image_pil.width
ratio_h = height / image_pil.height
if ratio_w < ratio_h:
# It must be fixed by width
resize_width = width
resize_height = round(ratio_w * image_pil.height)
else:
# Fixed by height
resize_width = round(ratio_h * image_pil.width)
resize_height = height
image_resize = image_pil.resize((resize_width, resize_height), Image.ANTIALIAS)
background = Image.new('RGBA', (width, height), (255, 255, 255, 255))
offset = (round((width - resize_width) / 2), round((height - resize_height) / 2))
background.paste(image_resize, offset)
return background.convert('RGB')
The accepted answer is great, I am just happy not to use OpenCV.
As #Nemanja mentioned, if you want to make it work for any aspect ration. Here is the snippet to use. I just twisted the code a bit.
from PIL import Image
def Reformat_Image_With_Ratio(ImageFilePath, desired_aspect_ratio):
image = Image.open(ImageFilePath, 'r')
width = image.width
height = image.height
img_aspect_ratio = width/height
if (img_aspect_ratio != desired_aspect_ratio):
bigside = width if width > height else height
other_side = int(bigside * desired_aspect_ratio)
background = Image.new('RGBA', (other_side, bigside), (255, 0, 0, 255))
offset = (int(round(((bigside - width) / 2), 0)), int(round(((bigside - height) / 2),0)))
background.paste(image, offset)
background.save('out4.png')
print("Image has been resized !")
else:
print("Image is already a valid aspect ratio, it has not been resized !")
Reformat_Image_With_Ratio('test.png', 9/16)
The other answer didn't work for me, I rewrote it and this worked:
def resize_with_pad(im, target_width, target_height):
'''
Resize PIL image keeping ratio and using white background.
'''
target_ratio = target_height / target_width
im_ratio = im.height / im.width
if target_ratio > im_ratio:
# It must be fixed by width
resize_width = target_width
resize_height = round(resize_width * im_ratio)
else:
# Fixed by height
resize_height = target_height
resize_width = round(resize_height / im_ratio)
image_resize = im.resize((resize_width, resize_height), Image.ANTIALIAS)
background = Image.new('RGBA', (target_width, target_height), (255, 255, 255, 255))
offset = (round((target_width - resize_width) / 2), round((target_height - resize_height) / 2))
background.paste(image_resize, offset)
return background.convert('RGB')

Get pixel location using mouse click/events

I wish to collect the pixel location (row-i, col-i) by right-clicking the mouse when the image is displayed.
This is a simple example about a picture downloaded from the internet:
import urllib
import cv2
from win32api import GetSystemMetrics
path_image = urllib.urlretrieve("http://www.bellazon.com/main/uploads/monthly_06_2013/post-37737-0-06086500-1371727837.jpg", "local-filename.jpg")[0]
img = cv2.imread(path_image,0)
width = GetSystemMetrics(0)
height = GetSystemMetrics(1)
scale_width = width / img.shape[1]
scale_height = height / img.shape[0]
scale = min(scale_width, scale_height)
window_width = int(img.shape[1] * scale)
window_height = int(img.shape[0] * scale)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.resizeWindow('image', window_width, window_height)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
At this point, I wish to understand the best way to collect and store the pixel locations in a list.
import urllib
import cv2
from win32api import GetSystemMetrics
#the [x, y] for each right-click event will be stored here
right_clicks = list()
#this function will be called whenever the mouse is right-clicked
def mouse_callback(event, x, y, flags, params):
#right-click event value is 2
if event == 2:
global right_clicks
#store the coordinates of the right-click event
right_clicks.append([x, y])
#this just verifies that the mouse data is being collected
#you probably want to remove this later
print right_clicks
path_image = urllib.urlretrieve("http://www.bellazon.com/main/uploads/monthly_06_2013/post-37737-0-06086500-1371727837.jpg", "local-filename.jpg")[0]
img = cv2.imread(path_image,0)
scale_width = 640 / img.shape[1]
scale_height = 480 / img.shape[0]
scale = min(scale_width, scale_height)
window_width = int(img.shape[1] * scale)
window_height = int(img.shape[0] * scale)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.resizeWindow('image', window_width, window_height)
#set mouse callback function for window
cv2.setMouseCallback('image', mouse_callback)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
you can use an array or list to store the pixels location in it and also you can store the pixel value as well.
Here, I'm using python 3.x
You can follow the below code. In that code I'm performing the two mouse click events.
One is for getting the pixel location using left mouse click, and second is for getting the specific pixel value at particular location in RGB image.
I'm also storing the pixel location value in refPt variable.
See below is the code.
import cv2
import numpy as np
#This will display all the available mouse click events
events = [i for i in dir(cv2) if 'EVENT' in i]
print(events)
#This variable we use to store the pixel location
refPt = []
#click event function
def click_event(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
print(x,",",y)
refPt.append([x,y])
font = cv2.FONT_HERSHEY_SIMPLEX
strXY = str(x)+", "+str(y)
cv2.putText(img, strXY, (x,y), font, 0.5, (255,255,0), 2)
cv2.imshow("image", img)
if event == cv2.EVENT_RBUTTONDOWN:
blue = img[y, x, 0]
green = img[y, x, 1]
red = img[y, x, 2]
font = cv2.FONT_HERSHEY_SIMPLEX
strBGR = str(blue)+", "+str(green)+","+str(red)
cv2.putText(img, strBGR, (x,y), font, 0.5, (0,255,255), 2)
cv2.imshow("image", img)
#Here, you need to change the image name and it's path according to your directory
img = cv2.imread("D:/pictures/abc.jpg")
cv2.imshow("image", img)
#calling the mouse click event
cv2.setMouseCallback("image", click_event)
cv2.waitKey(0)
cv2.destroyAllWindows()
Note: One thing you need to remember that you have to put same name for the namedWindow. It should be same. In my code, I'm using the same name "image" for all the window.
You can do the same thing for multiple images as well. You just need to pass an list instead of single image.
If you want to store the pixel location in some text file, then you can also do it as follow:
Give the name of the variable where you are storing the pixel location value. I used refPt for storing the value. so, I used it here as follow:
import csv
with open("D:/pixelLocation.txt", 'w', newline='') as f:
w = csv.writer(f)
w.writerows(refPt)

Categories

Resources