Have a look at the image and it will give you the better idea what I want to achieve. I want to rotate the image and fill the black part of image just like in required image.
# Read the image
img = cv2.imread("input.png")
# Get the image size
h, w = img.shape[:2]
# Define the rotation matrix
M = cv2.getRotationMatrix2D((w/2, h/2), 30, 1)
# Rotate the image
rotated = cv2.warpAffine(img, M, (w, h))
mask = np.zeros(rotated.shape[:2], dtype=np.uint8)
mask[np.where((rotated == [0, 0, 0]).all(axis=2))] = 255
img_show(mask)
From the code I am able to get the mask of black regions. Now I want to replace these black regions with the image portion as shown in the image 1. Any better solution how can I achieve this.
Use the borderMode parameter of warpAffine.
You want to pass the BORDER_WRAP value.
Here's the result. This does exactly what you described with your first picture.
I have an approach. You can first create a larger image consisting of 3 * 3 times your original image. When you rotate this image and only cut out the center of this large image, you have your desired result.
import cv2
import numpy as np
# Read the image
img = cv2.imread("input.png")
# Get the image size of the origial image
h, w = img.shape[:2]
# make a large image containing 3 copies of the original image in each direction
large_img = np.tile(img, [3,3,1])
cv2.imshow("large_img", large_img)
# Define the rotation matrix. Rotate around the center of the large image
M = cv2.getRotationMatrix2D((w*3/2, h*3/2), 30, 1)
# Rotate the image
rotated = cv2.warpAffine(large_img, M, (w*3, h*3))
# crop only the center of the image
cropped_image = rotated[w:w*2,h:h*2,:]
cv2.imshow("cropped_image", cropped_image)
cv2.waitKey(0)
Related
I'm making a script that copies an "anomaly" image and pastes it in random places from an original image. Like this:
Original Imagem
Anomaly Image:
Output Imagem Example:
But at the same time that the image with the anomaly is generated, I need to generate a mask where the area of the anomaly that I pasted is white and the rest of the image is black. Like this (I did it manually in Gimp):
Output image mask example:
How can I do this automatically at the same time as the anomaly image is generated? Below the code I'm using:
from PIL import Image
import random
anomaly = Image.open("anomaly_transp.png") # anomaly image with transparent background
image_number = 1 # number of images
w, h = anomaly.size
offset_x, offset_y = 480-w, 512-h # offsets to avoid incorrect paste area from original image
for i in range(image_number):
original = Image.open("Crop_120.png") # original good image
x1 = random.randint(0,offset_x)
y1 = random.randint(0,offset_y)
area = (x1, y1, x1+w, y1+h)
original.paste(anomaly, area, anomaly)
original.save("output_"+str(i)+".png") # save output image
original.close()
You can use
alpha = anomaly.split()[-1]
to fetch the alpha plane of your transparent image. You can then paste that into an all black image of the right size to get your mask.
I'm trying to add a chessboard to an image in order to find the distortion coefficients. However when I use the function addWeighted() the black areas of my chessboard are transparant.
First I warp my chessboard image with the functions findHomography() and warpPerspective()
Then I try to add the image of the scene and the warped chessboard together with addWeighted(). What do I need to do in order to get it not transparant?
Edit code:
input_1 = cv2.imread('RV_CV_Assignment_3_image_1.jpg')
imageSize = input_1.shape[:2]
chessboard = cv2.imread('Chessboard.jpg')
boardSize = np.float32([[0,0],[3632,0],[0,2816],[3632,2816]])
# These are the corner coordinates for the chessboard in the image. For now I do this manually
cornersBoard1 = np.float32([[348,233],[2004,233],[291,1555],[2025,1555]])
homography1, status1 = cv2.findHomography(boardSize,cornersBoard1)
warpBoard1 = cv2.warpPerspective(chessboard, homography1, (imageSize[1], imageSize[0]))
imgChessboard1 = cv2.addWeighted(input_1, 1, warpBoard1, 1, 0)
cv2.namedWindow('Chessboard in image 1', cv2.WINDOW_NORMAL)
cv2.imshow('Chessboard in image 1',imgChessboard1)
Here is one way to do that in Python/OpenCV. Make sure your "chessboard" image has black mapped to 1 rather than 0. Then in your perspective warp, be sure the non-image background is colored as pure black, i.e. 0. Then use np.where to blend the two images.
Here is your code modified accordingly,
import cv2
import numpy as np
input_1 = cv2.imread('buildings.jpg')
imageSize = input_1.shape[:2]
chessboard = cv2.imread('checks.png')
boardSize = np.float32([[0,0],[3632,0],[0,2816],[3632,2816]])
# modify chessboard to map (0,0,0) to (1,1,1) so no pure black
chessboard[np.where((chessboard == [0,0,0]).all(axis=2))] = [1,1,1]
# These are the corner coordinates for the chessboard in the image. For now I do this manually
cornersBoard1 = np.float32([[348,233],[2004,233],[291,1555],[2025,1555]])
homography1, status1 = cv2.findHomography(boardSize,cornersBoard1)
# make sure background of warpParspective is pure black
warpBoard1 = cv2.warpPerspective(chessboard, homography1, (imageSize[1], imageSize[0]), borderMode=cv2.BORDER_CONSTANT, borderValue=(0,0,0))
# use np.where to blend the two images with the chessboard over the buildings
imgChessboard1 = np.where(warpBoard1==0, input_1, warpBoard1)
cv2.namedWindow('Chessboard in image 1', cv2.WINDOW_NORMAL)
cv2.imshow('Chessboard in image 1',imgChessboard1)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('checkerboard_on_buildings.jpg', imgChessboard1)
Result:
i'm totally new to this kind of things, i used SLIC to get superpixels from an image, now i have extracted the single superpixel detected but it's like the whole start img dimension except that there is the superpixel and the rest of the image is black, i'm sorry for my bad english, i'll try to explain below.
import cv2
import numpy as np
from skimage.segmentation import slic
myimg = cv2.imread('4.5.jpg')
segments = slic(myimg, n_segments=200, compactness=10, sigma=1)
for i, segVal in enumerate(np.unique(segments)):
mask = np.zeros(myimg.shape[:2], dtype = "uint8")
mask[segments == segVal] = 255
cv2.imwrite('output.png', cv2.bitwise_and(myimg, myimg, mask = mask))
#show the masked region
#cv2.imshow("Mask", mask)
cv2.imshow("Applied", cv2.bitwise_and(myimg, myimg, mask = mask))
cv2.waitKey(1)
that's actually my code to get superpixels, but when i store the single superpixel what i get is in that link (i'm not allowed yet to embed images):
superpixel
now as u can see there is a big black region with the H and W of the original image and the superpixel, i wish to crop only a "rectangle or square" with the superpixel region, how can i do that? thank you and sorry for my english
For this task you can use cv2.findContours. Refer to its documentation to know how to use it. After finding out the contours which will just be one in your case you can use
x,y,w,h = cv2.boundingRect(cnt)
where x, y are the coordinates of top left corner and w, h are the width and height of the rectangle. Now we can know all the points of the required recatngle and you can crop it using numpy indexing.
I want to make an affine transformation and afterwards use nearest neighbor interpolation while keeping the same dimensions for input and output images. I use for example the scaling transformation T= [[2,0,0],[0,2,0],[0,0,1]]. Any idea how can I fill the black pixels with nearest neighbor ? I tryied giving them the min value of neighbors' intensities. For ex. if a pixel has neighbors [55,22,44,11,22,55,23,231], I give it the value of min intensity: 11. But the result is not anything clear..
import numpy as np
from matplotlib import pyplot as plt
#Importing the original image and init the output image
img = plt.imread('/home/left/Desktop/computerVision/SET1/brain0030slice150_101x101.png',0)
outImg = np.zeros_like(img)
# Dimensions of the input image and output image (the same dimensions)
(width , height) = (img.shape[0], img.shape[1])
# Initialize the transformation matrix
T = np.array([[2,0,0], [0,2,0], [0,0,1]])
# Make an array with input image (x,y) coordinations and add [0 0 ... 1] row
coords = np.indices((width, height), 'uint8').reshape(2, -1)
coords = np.vstack((coords, np.zeros(coords.shape[1], 'uint8')))
output = T # coords
# Arrays of x and y coordinations of the output image within the image dimensions
x_array, y_array = output[0] ,output[1]
indices = np.where((x_array >= 0) & (x_array < width) & (y_array >= 0) & (y_array < height))
# Final coordinations of the output image
fx, fy = x_array[indices], y_array[indices]
# Final output image after the affine transformation
outImg[fx, fy] = img[fx, fy]
The input image is:
The output image after scaling is:
well you could simply use the opencv resize function
import cv2
new_image = cv2.resize(image, new_dim, interpolation=cv.INTER_AREA)
it'll do the resize and fill in the empty pixels in one go
more on cv2.resize
If you need to do it manually, then you could simply detect dark pixels in resized image and change their value to mean of 4 neighbour pixels (for example - it depends on your required alghoritm)
See: nereast neighbour, bilinear, bicubic, etc.
Can someone tell me how to rotate only part of an image like this:
How to find coordinate / center of this image:
i can rotate all pict using this
from PIL import Image
def rotate_image():
img = Image.open("nime1.png")
img.rotate(45).save("plus45.png")
img.rotate(-45).save("minus45.png")
img.rotate(90).save("90.png")
img.transpose(Image.ROTATE_90).save("90_trans.png")
img.rotate(180).save("180.png")
if __name__ == '__main__':
rotate_image()
You can crop an area of the picture as a new variable. In this case, I cropped a 120x120 pixel box out of the original image. It is rotated by 90 and then pasted back on the original.
from PIL import Image
img = Image.open('./image.jpg')
sub_image = img.crop(box=(200,0,320,120)).rotate(90)
img.paste(sub_image, box=(200,0))
So I thought about this a bit more and crafted a function that applies a circular mask to the cropped image before rotations. This allows an arbitrary angle without weird effects.
def circle_rotate(image, x, y, radius, degree):
img_arr = numpy.asarray(image)
box = (x-radius, y-radius, x+radius+1, y+radius+1)
crop = image.crop(box=box)
crop_arr = numpy.asarray(crop)
# build the cirle mask
mask = numpy.zeros((2*radius+1, 2*radius+1))
for i in range(crop_arr.shape[0]):
for j in range(crop_arr.shape[1]):
if (i-radius)**2 + (j-radius)**2 <= radius**2:
mask[i,j] = 1
# create the new circular image
sub_img_arr = numpy.empty(crop_arr.shape ,dtype='uint8')
sub_img_arr[:,:,:3] = crop_arr[:,:,:3]
sub_img_arr[:,:,3] = mask*255
sub_img = Image.fromarray(sub_img_arr, "RGBA").rotate(degree)
i2 = image.copy()
i2.paste(sub_img, box[:2], sub_img.convert('RGBA'))
return i2
i2 = circle_rotate(img, 260, 60, 60, 45)
i2
You can solve this problem as such. Say you have img = Image.open("nime1.png")
Create a copy of the image using img2 = img.copy()
Create a crop of img2 at the desired location using img2.crop(). You can read how to do this here
Paste img2 back onto img at the appropriate location using img.paste()
Notes:
To find the center coordinate, you can divide the width and height by 2 :)