Can't center duplicate picture - python

So for this code to work properly, i need it to center the new image in the black space with borders around it. I've been trying to take the first image dimensions and subtract the new enlarged empty dimensions but I can't seem to get it to work. I'm not sure what to do at this point. I've managed to duplicate the picture i just need to center it now.
import numpy as np
# read in image (in the same folder)
image = cv2.imread("cones11.png")
# get size of image
numRows = image.shape[0] # height of image
numCols = image.shape[1] # width of image
print(image.shape[0])
print(image.shape[1])
#scalar
scalar = 1.2
#newdimensions nxn
n = int (scalar * numRows)
n1 = int(scalar * numCols)
shift = n/2
shift1 = n1/2
# create an empty color image
emptyIm = np.zeros((n, n1, 3)) # (size, data type)
# iterate over all the pixels of your image
for i in range(numRows): # iterate over height of image, y-coordinates
for j in range(numCols): # iteratve over the width of image, x-coordinates
# access values at a pixel:
# image[i][j][0]: blue value stored at pixel (i,j)
# image[i][j][1]: green value stored at pixel (i,j)
# image[i][j][2]: red value stored at pixel (i,j)
#image[i][j][0] = emptyIm[i][j][0]
#image[i][j][1] = emptyIm[i][j][1]
#image[i][j][2] = emptyIm[i][j][2]
emptyIm[i,j] = emptyIm[j,i] - image[int(shift)-1, int(shift1)-1]
emptyIm[i][j][0] = image[i][j][0]
emptyIm[i][j][1] = image[i][j][1]
emptyIm[i][j][2] = image[i][j][2]
#emptyIm[i][j] = emptyIm[i+n][i+n]
#enlarging image
# n = 2*emptyIm[i][j]
cv2.imshow("xd", image)
cv2.imshow("enlarged", emptyIm/255.0)
cv2.waitKey(0)```

Related

How to print text as watermark on images vertically in Python

I Here is my Code
# Json file in which Easyocr anotations have saved.
img = cv2.imread('dummy.jpg')
img1 = img.copy()
#rotoated because anotation have according to vertical alignment of image i have matched the orientation
img1=cv2.rotate(img1,rotateCode=cv2.ROTATE_90_CLOCKWISE)
rects = []
with open('dummy.json') as jsn:
jsn_dict = json.load(jsn)
for k in jsn_dict['textAnnotations']:
vertices= k['boundingPoly']['vertices']
cv2.rectangle(img1,list(vertices[2].values()),list(vertices[0].values()),[0,255,0],10)
# I want to put predicted text on top of bounding boxes vertically because my image is rotated anti clockwise
cv2.putText(img1, k['description'], list(vertices[0].values()),cv2.FONT_HERSHEY_SIMPLEX,5,[0,255,0],5)
I have the code mentioned above I am labelling the recognized text. First step is, I put the image into the OCR model and it returns some values according to the image, in which we have three values for every detected text. These values are the vertex of the bounding box, the text that was recognized, and the accuracy percentage. But my problem is that my image was rotated by the Exif orientation value but cv2 read it as a zero angle and my text is printing horizontally. I want to print text on an image vertically. I have tried so many times but could not resolve my problem. I hope I have explained it well.
Try this one
import cv2
def transparentOverlay(src, overlay, pos=(0, 0), scale=1):
"""
:param src: Input Color Background Image
:param overlay: transparent Image (BGRA)
:param pos: position where the image to be blit.
:param scale : scale factor of transparent image.
:return: Resultant Image
"""
overlay = cv2.resize(overlay, (0, 0), fx=scale, fy=scale)
h, w, _ = overlay.shape # Size of foreground
rows, cols, _ = src.shape # Size of background Image
y, x = pos[0], pos[1] # Position of foreground/overlay image
# loop over all pixels and apply the blending equation
for i in range(h):
for j in range(w):
if x + i >= rows or y + j >= cols:
continue
alpha = float(overlay[i][j][3] / 255.0) # read the alpha channel
src[x + i][y + j] = alpha * overlay[i][j][:3] + (1 - alpha) * src[x + i][y + j]
return src
def addImageWatermark(LogoImage,MainImage,opacity,pos=(10,100),):
opacity = opacity / 100
OriImg = cv2.imread(MainImage, -1)
waterImg = cv2.imread(LogoImage, -1)
tempImg = OriImg.copy()
print(tempImg.shape)
overlay = transparentOverlay(tempImg, waterImg, pos)
output = OriImg.copy()
# apply the overlay
cv2.addWeighted(overlay, opacity, output, 1 - opacity, 0, output)
cv2.imshow('Life2Coding', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
addImageWatermark('./logo.png','./hanif.jpg',100,(10,100))
Rotate your image 90º clockwise, add the text, and rotate the image back to the original.
# Rotate 90º clockwise
img_rot = cv2.rotate(img1 , cv2.ROTATE_90_CLOCKWISE)
# Add your text here, adjusting x and y coordinates to the new orientation.
# The new adjusted coordinates will be:
# (x2, y2) = (original_height - y, x)
# [...]
# Rotate back
img1 = cv2.rotate(img_rot, cv2.ROTATE_90_CLOCKWISE)

affine transformation using nearest neighbor in python

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.

Unable to increase the region of interest of an image

I am trying to increase the region of interest of an image using the below algorithm.
First, the set of pixels of the exterior border of the ROI is de termined, i.e., pixels that are outside the ROI and are neighbors (using four-neighborhood) to pixels inside it. Then, each pixel value of this set is replaced with the mean value of its neighbors (this time using eight-neighborhood) inside the ROI. Finally, the ROI is expanded by inclusion of this altered set of pixels. This process is repeated and can be seen as artificially increasing the ROI.
The pseudocode is below -
while there are border pixels:
border_pixels = []
# find the border pixels
for each pixel p=(i, j) in image
if p is not in ROI and ((i+1, j) in ROI or (i-1, j) in ROI or (i, j+1) in ROI or (i, j-1) in ROI) or (i-1,j-1) in ROI or (i+1,j+1) in ROI):
add p to border_pixels
# calculate the averages
for each pixel p in border_pixels:
color_sum = 0
count = 0
for each pixel n in 8-neighborhood of p:
if n in ROI:
color_sum += color(n)
count += 1
color(p) = color_sum / count
# update the ROI
for each pixel p=(i, j) in border_pixels:
set p to be in ROI
Below is my code
img = io.imread(path_dir)
newimg = np.zeros((584, 565,3))
mask = img == 0
while(1):
border_pixels = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
for k in range(0,3):
if(i+1<=583 and j+1<=564 and i-1>=0 and j-1>=0):
if ((mask[i][j][k]) and ((mask[i+1][j][k]== False) or (mask[i-1][j][k]==False) or (mask[i][j+1][k]==False) or (mask[i][j-1][k]==False) or (mask[i-1][j-1][k] == False) or(mask[i+1][j+1][k]==False))):
border_pixels.append([i,j,k])
if len(border_pixels) == 0:
break
for (each_i,each_j,each_k) in border_pixels:
color_sum = 0
count = 0
eight_neighbourhood = [[each_i-1,each_j],[each_i+1,each_j],[each_i,each_j-1],[each_i,each_j+1],[each_i-1,each_j-1],[each_i-1,each_j+1],[each_i+1,each_j-1],[each_i+1,each_j+1]]
for pix_i,pix_j in eight_neighbourhood:
if (mask[pix_i][pix_j][each_k] == False):
color_sum+=img[pix_i,pix_j,each_k]
count+=1
print(color_sum//count)
img[each_i][each_j][each_k]=(color_sum//count)
for (i,j,k) in border_pixels:
mask[i,j,k] = False
border_pixels.remove([i,j,k])
io.imsave("tryout6.png",img)
But it is not doing any change in the image.I am getting the same image as before
so I tried plotting the border pixel on a black image of the same dimension for the first iteration and I am getting the below result-
I really don't have any idea where I am doing wrong here.
Here's a solution that I think works as you have requested (although I agree with #Peter Boone that it will take a while). My implementation has a triple loop, but maybe someone else can make it faster!
First, read in the image. With my method, the pixel values are floats between 0 and 1 (rather than integers between 0 and 255).
import urllib
import matplotlib.pyplot as plt
import numpy as np
from skimage.morphology import binary_dilation, binary_erosion, disk
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
# create a file-like object from the url
f = urllib.request.urlopen("https://i.stack.imgur.com/JXxJM.png")
# read the image file in a numpy array
# note that all pixel values are between 0 and 1 in this image
a = plt.imread(f)
Second, add some padding around the edges, and threshold the image. I used Otsu's method, but #Peter Boone's answer works well, too.
# add black padding around image 100 px wide
a = np.pad(a, ((100,100), (100,100), (0,0)), mode = "constant")
# convert to greyscale and perform Otsu's thresholding
grayscale = rgb2gray(a)
global_thresh = threshold_otsu(grayscale)
binary_global1 = grayscale > global_thresh
# define number of pixels to expand the image
num_px_to_expand = 50
The image, binary_global1 is a mask that looks like this:
Since the image is three channels (RGB), I process the channels separately. I noticed that I needed to erode the image by ~5 px because the outside of the image has some unusual colors and patterns.
# process each channel (RGB) separately
for channel in range(a.shape[2]):
# select a single channel
one_channel = a[:, :, channel]
# reset binary_global for the each channel
binary_global = binary_global1.copy()
# erode by 5 px to get rid of unusual edges from original image
binary_global = binary_erosion(binary_global, disk(5))
# turn everything less than the threshold to 0
one_channel = one_channel * binary_global
# update pixels one at a time
for jj in range(num_px_to_expand):
# get 1 px ring of to update
px_to_update = np.logical_xor(binary_dilation(binary_global, disk(1)),
binary_global)
# update those pixels with the average of their neighborhood
x, y = np.where(px_to_update == 1)
for x, y in zip(x,y):
# make 3 x 3 px slices
slices = np.s_[(x-1):(x+2), (y-1):(y+2)]
# update a single pixel
one_channel[x, y] = (np.sum(one_channel[slices]*
binary_global[slices]) /
np.sum(binary_global[slices]))
# update original image
a[:,:, channel] = one_channel
# increase binary_global by 1 px dilation
binary_global = binary_dilation(binary_global, disk(1))
When I plot the output, I get something like this:
# plot image
plt.figure(figsize=[10,10])
plt.imshow(a)
This is an interesting idea. You're going to want to use masks and some form of mean ranks to accomplish this. Going pixel by pixel will take you a while, instead you want to use different convolution filters.
If you do something like this:
image = io.imread("roi.jpg")
mask = image[:,:,0] < 30
just_inside = binary_dilation(mask) ^ mask
image[~just_inside] = [0,0,0]
you will have a mask representing just the pixels inside of the ROI. I also set the pixels not in that area to 0,0,0.
Then you can get the pixels just outside of the roi:
just_outside = binary_erosion(mask) ^ mask
Then get the mean bilateral of each channel:
mean_blue = mean_bilateral(image[:,:,0], selem=square(3), s0=1, s1=255)
#etc...
This isn't exactly correct, but I think it should put you in the right direction. I would check out image.sc if you have more general questions about image processing. Let me know if you need more help as this was more general direction than working code.

How to concatenate images of different shapes using python and opencv?

I have some images(say 5) and each having different shapes. I want to concatenate into one single image for my project report. Can you please provide an easy way using opencv and python?
The resulting image is similar to below.
In numpy I tried something like this, it works but only for two images.
r = np.concatenate((images[1][:, :, 1], images[1][:, :, 3]), axis=1)
Getting the results that you show in the screenshot might require some more tinkering, but simply stacking the images on top of eachother can be acomplished like this:
import cv2
import numpy as np
image_names = ['original_field_1_0.PNG','original_field_1_1.PNG','original_field_1_3.PNG','original_field_1_4.PNG','original_field_1_5.PNG']
images = []
max_width = 0 # find the max width of all the images
total_height = 0 # the total height of the images (vertical stacking)
for name in image_names:
# open all images and find their sizes
images.append(cv2.imread(name))
if images[-1].shape[1] > max_width:
max_width = images[-1].shape[1]
total_height += images[-1].shape[0]
# create a new array with a size large enough to contain all the images
final_image = np.zeros((total_height,max_width,3),dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in images:
# add an image to the final array and increment the y coordinate
final_image[current_y:image.shape[0]+current_y,:image.shape[1],:] = image
current_y += image.shape[0]
cv2.imwrite('fin.PNG',final_image)
The basic idea is to find the total size of the images first, then create an array of that size and finally set the pixels in those ranges to that of each individual image while iterating downwards (or sideways, depending on what you want).
You can also implement threshold values for when you want to start another row or column.
This modification of #ajayramesh's solution worked for me. This function takes in a list of images and outputs a single image where all input images are stacked vertically:
def get_one_image(img_list):
max_width = 0
total_height = 200 # padding
for img in img_list:
if img.shape[1] > max_width:
max_width = img.shape[1]
total_height += img.shape[0]
# create a new array with a size large enough to contain all the images
final_image = np.zeros((total_height, max_width, 3), dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in img_list:
# add an image to the final array and increment the y coordinate
image = np.hstack((image, np.zeros((image.shape[0], max_width - image.shape[1], 3))))
final_image[current_y:current_y + image.shape[0], :, :] = image
current_y += image.shape[0]
return final_image
I modified code to make it a simple function, may be useful for others.
def get_one_image(images):
img_list = []
padding = 200
for img in images:
img_list.append(cv2.imread(img))
max_width = []
max_height = 0
for img in img_list:
max_width.append(img.shape[0])
max_height += img.shape[1]
w = np.max(max_width)
h = max_height + padding
# create a new array with a size large enough to contain all the images
final_image = np.zeros((h, w, 3), dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in img_list:
# add an image to the final array and increment the y coordinate
final_image[current_y:image.shape[0] + current_y, :image.shape[1], :] = image
current_y += image.shape[0]
cv2.imwrite('out.png', final_image)

how can I efficiently pad a RGB pixel to make it the center pixel of a resulting image using numpy

I have an image consisting of 100 pixels. for each pixel, I want to pad it with zeros (if on the edge) so that it's in the center, concatenate with neighboring pixels and generate a new 10x10 image. Thus I want to generate 100 images from the original image by sliding through each pixel along the row. e.g. for pixel[0,0], I want to add 4 zero columns on right, 4 zero rows on top, neighboring 5 column pixels on right and neighboring 5 row pixels on the bottom.
Can someone guide me on how this is done for a RGB image with numpy?
def unpickle_im(file, type):
import Image
im1 = Image.open(file)
im1p = np.asarray(im1, dtype=type)
return im1p
imc2p = unpickle_im('tmp/RGB-00000.png', 'float32')
##imc2p.shape = (10,10,3)
padded = np.zeros(10,10,3) ##Create a padded image filled with zeros
for i in xrange(im2cp.shape[0]):
for j in xrange(im2cp.shape[1]):
if(i < 5 or j < 5) :
new_im2cp = np.pad(im2cp[i:5, j:5], ((4-i,4-j),(0,0)))
else:
new_im2cp = np.pad(im2cp[i-4:i+5, j-4:j+5])
edit: adding the correct snippet after #dabhaid's post:
from PIL import Image
import numpy as np, time
im_array = np.random.rand(10,10,3)
pad = 4
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1] ):
temp_im = padded_array[i:i+10, j:j+10]
# print temp_im.shape
if i == 0 and j == 0:
new_im = temp_im[np.newaxis,...]
else:
new_im = np.vstack([new_im, temp_im[np.newaxis,...]])
I'm going to assume you have an RGB image (rather than an RGBA). As per the comments, is this what you want?
from PIL import Image
import numpy as np
image = Image.open('100.png')
im_array = np.array(image)
stack = np.array(100, 20, 20, 3) #100 of the padded arrays
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1]):
padded = np.zeros((20,20,3))
padded[9][9] = im_array[i][j]
stack[i*j] = padded
It seems wasteful, memory-wise.
edit in response to question update
instead of padding the new images conditionally, pad the original image and then just copy sub-images out of it:
from PIL import Image
import numpy as np
image = Image.open('100.png')
im_array = np.array(image)
pad = 4 #pixels
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
# pad 4 elements to the left, right, up and down, but leave the pixel values alone
# default value is zero
for i in xrange(im_array.shape[0] - (pad + pad+1)):
for j in xrange(im_array.shape[0] - (pad + pad+1)):
new_imarray = padded_array[i:i+9, j:j+9]
# do what you need with the new image
from PIL import Image
import numpy as np, time
im_array = np.random.rand(10,10,3)
pad = 4
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1] ):
temp_im = padded_array[i:i+10, j:j+10]
# print temp_im.shape
if i == 0 and j == 0:
new_im = temp_im[np.newaxis,...]
else:
new_im = np.vstack([new_im, temp_im[np.newaxis,...]])

Categories

Resources