Moviepy: Resize image with black borders - python

I have a problem with resizing videos in moviepy. When I use the clip.resize(1920,1080) function, it stretches the image. I want it to stretch the image, keep the aspect ratio, but add black borders to it (to fill the aspect ratio).
This is the source image/video (resolution: 670 x 844)
This is how I want it to look (resolution: 1920 x 1080)

Mix it with some black image in resolution you whish:
video = mp.VideoFileClip("/media/pi/video.mp4")
black_image = (mp.ImageClip("black_picture_1920x1080.jpg"))
mp.CompositeVideoClip([black_image, video.set_position("center")])

Related

Change background color for Thresholderd image

I have been trying to write a code to extract cracks from an image using thresholding. However, I wanted to keep the background black. What would be a good solution to keep the outer boundary visible and the background black. Attached below is the original image along with the threshold image and the code used to extract this image.
import cv2
#Read Image
img = cv2.imread('Original.png')
# Convert into gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Image processing ( smoothing )
# Averaging
blur = cv2.blur(gray,(3,3))
ret,th1 = cv2.threshold(blur,145,255,cv2.THRESH_BINARY)
inverted = np.invert(th1)
plt.figure(figsize = (20,20))
plt.subplot(121),plt.imshow(img)
plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(inverted,cmap='gray')
plt.title('Threshold'),plt.xticks([]), plt.yticks([])
Method 1
Assuming the circle in your images stays in one spot throughout your image set you can manually create a black 'mask' image with a white hole in the middle, then overlay it on the final inverted image.
You can easily make the mask image using your favorite image editor's magic wand tool.
I made this1 by also expanding the circle inwards by one pixel to take into account some of the pixels the magic wand tool couldn't catch.
You would then use the mask image like this:
mask = cv2.imread('/path/to/mask.png')
masked = cv2.bitwise_and(inverted, inverted, mask=mask)
Method 2
If the circle does NOT stay is the same spot throughout your entire image set you can try to make the mask from all the fully black pixels in your original image. This assumes that the 'sample' itself (the thing with the cracks) does not contain fully black pixels. Although this will result in the text on the bottom left to be left white.
# make all the non black pixels white
_,mask = cv2.threshold(gray,1,255,cv2.THRESH_BINARY)
1 The original is not the same size as your inverted image and thus the mask I made won't actually fit, you're gonna have to make it yourself.

Rotating an image in openCV without the black box and without cropping

So I looked a here and there and it seems like it's a common problem. Though, I have a specific need that wasn't solved in the existing threads.
The main idea of my school project is to simulate a tattoo on your skin. For that, OpenCV detects the arm thanks to the skin color.
Thanks to the cv2.getRotationMatrix2D and cv2.warpAffine, I can rotate the tatoo with the arm.
#areaAngle is the inclination in degrees of the region of interest
N = cv2.getRotationMatrix2D((tatWidth/2,tatHeight/2),areaAngle,1)
#imgTatoo is the mustache image
roTatoo=cv2.warpAffine(imgTatoo,N,(tatWidth,tatHeight))
But my problem is this one :
When the arm is straight, everything is fine (image)
While when I tilt the arm, a magnificent black box appears (image again).
One of the proposed solutions was to crop the image using "bigger rectangle in the area". The thing is i want to keep the full tattoo and not just a cropped part.
Any idea how to do that?
Thanks
EDIT : I tried to resize the mask to match the diagonal height but the problem is that because of these lines of code:
tatoo=cv2.resize(imgTatoo,(tatWidth,tatHeight),interpolation=cv2.INTER_AREA)
mask2=cv2.resize(tatMask,(tatWidth,tatHeight),interpolation=cv2.INTER_AREA)
mask2inv=cv2.resize(invTatMask,(tatWidth,tatHeight),interpolation=cv2.INTER_AREA)
and further away
#create a ROI mask
roi = frame[fy1:fy2,fx1:fx2]
# print(roi.shape)
#merge the roi mask with the tatoo and the inverted tatoo masks
roi_bg = cv2.bitwise_and(roi,roi,mask = mask2inv)
roi_fg = cv2.bitwise_and(tatoo,tatoo,mask = mask2)
# print(roi_bg.shape,roi_fg.shape)
#merge the background and foreground ROI masks
dst = cv2.add(roi_fg,roi_bg)
if I try to resize the mask, i have to resize the tattoo image since the arrays need to be the same size.

How can I change the background of only white pixels?

I have two grayscale images of the same size, one of them is this one:
I'm trying to add a background to this image, which is to just change the white pixels to the respective pixels in the other picture. The best result I've managed to do is just a bitwise and of all the pixels of both pictures but the resultant picture is distorted inside James Bond. I also tried a weighted add between the two pictures but when I increase the weight of the James Bond image, it's white pixels are visible in the resultant image.
To combine with a second image, ensure that both images have the same dimensions (which yours do). They can then be combined
import cv2
img_jb = cv2.imread('james_bond.png')
img_007 = cv2.imread('007_logo.png')
height, width, channels = img_jb.shape
img_007_resized = cv2.resize(img_007, (width, height), interpolation=cv2.INTER_CUBIC)
threshold = img_jb > 240
img_jb[threshold] = img_007_resized[threshold]
cv2.imwrite('james_bond_logo.png', img_jb)
Giving you:
numpy allows you to work on the indexes of an array that match a given criteria. This has the effect of copying pixels from the background image into the foreground image where the foreground image has a value above 240.

Pillow handles PNG files incorrectly

I can successfully convert a rectangular image into a png with transparent rounded corners like this:
However, when I take this transparent cornered image and I want to use it in another image generated with Pillow, I end up with this:
The transparent corners become black. I've been playing around with this for a while but I can't find any way in which the transparent parts of an image don't turn black once I place them on another image with Pillow.
Here is the code I use:
mask = Image.open('Test mask.png').convert('L')
im = Image.open('boat.jpg')
im.resize(mask.size)
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
im = Image.open('output.png')
image_bg = Image.new('RGBA', (1292,440), (255,255,255,100))
image_fg = im.resize((710, 400), Image.ANTIALIAS)
image_bg.paste(image_fg, (20, 20))
image_bg.save('output2.jpg')
Is there a solution for this? Thanks.
Per some suggestions I exported the 2nd image as a PNG, but then I ended up with an image with holes in it:
Obviously I want the second image to have a consistent white background without holes.
Here is what I actually want to end up with. The orange is only placed there to highlight the image itself. It's a rectangular image with white background, with a picture placed into it with rounded corners.
If you paste an image with transparent pixels onto another image, the transparent pixels are just copied as well. It looks like you only want to paste the non-transparent pixels. In that case, you need a mask for the paste function.
image_bg.paste(image_fg, (20, 20), mask=image_fg)
Note the third argument here. From the documentation:
If a mask is given, this method updates only the regions indicated by
the mask. You can use either "1", "L" or "RGBA" images (in the latter
case, the alpha band is used as mask). Where the mask is 255, the
given image is copied as is. Where the mask is 0, the current value
is preserved. Intermediate values will mix the two images together,
including their alpha channels if they have them.
What we did here is provide an RGBA image as mask, and use the alpha channel as mask.

What happens to pixels when an image is resized?

I have this original image of size 800 x 600px
What I have to do is to resize the image to 625 x 480px and filter all the land areas. I have found that the BGR values of the land part is (95,155,212). This is the code I used to filter all the and areas:
image[np.where((image == [95,155,212]).all(axis = 2))] = [0,0,0]
If I resize first, then filter, here is the output:
If I filter first then resize, I get my desired output:
So my first question is what happened to the image's pixels when it is resized?
I have this original image of size 712 x 480px
When I applied filtering to remove the land area, I get an output like the second image from the top. 2nd question, is there any way for me to fix this problem?
most likely the resizing changes the border colors to something between land color and black outline.
This screws up your filter because you need higher ranges for land color and also the border line color (Black) can have color artifacts. These artifact are what is left after filtering in your example. If you pick their colors they should be outside your selected range.
How to repair?
use nearest neighbor resizing
this will left the colors as are but the resized image is not as pretty ...
change filters to handle close colors not just range of color
so change to something like flood fill and fill all pixels that do not differ too much from each other. You need 2 thresholds for this:
absolute (is the color range total big one)
relative (is the max change of neighboring pixels small one)
now just recolor the resized image or change the filter function to this ...
Image sizes onscreen and in print
The size of an image when you view it onscreen is different from its size when you print it. If you understand these differences, you can develop a better understanding of which settings to change when you resize an image.
Screen size
The screen resolution of your monitor is the number of pixels it can display. For example, a monitor with a screen resolution of 640 x 480 pixels displays 640 pixels for the width and 480 pixels for the height. There are several different screen resolutions you can use, and the physical size of the monitor screen usually determines the resolutions available. For example, large monitors typically display higher resolutions than small monitors because they have more pixels.
Image size onscreen
Images are of a fixed pixel size when they appear on your monitor. Your screen resolution determines how large the image appears onscreen. A monitor set to 640 x 480 pixels displays fewer pixels than a monitor displaying 1024 x 768 pixels. Therefore, each of the pixel on the 640 x 480 pixel monitor is larger than each pixel displayed on the 1024 x 768 pixel monitor.
A 100 x 100-pixel image uses about one-sixth of the screen at 640 x 480, but it takes up only about one-tenth of the screen at 1024 x 768. Therefore, the image looks smaller at 1024 x 768 pixels than at 640 x 480 pixels
The Following Parameters change when you resize an image
Pixel dimensions: The width and height of the image.
Image size :
Document size: Physical size of the image when printed, including a width and height.
Image resolution when printed: This value appears in pixels per inch or pixels per centimeter.
In Photoshop the physical size, resolution, and pixel dimensions of an image are calculated as follows:
Physical size = resolution x pixel dimensions
Resolution = physical size / pixel dimensions
Pixel dimensions = physical size / resolution
For more info on this you can check Adobe's Document on Image resizing

Categories

Resources