I want to make a function which generate a dataset, The object will be place on the black image at different position with different angle, different size and place randomly maximum up to 20 time in image. and Save the x,y and angle position in the text file.
The following image is for five objects at different position and angle.
import numpy as np
import cv2
patch=cv2.imread('imagersult.png')
img = np.zeros((2048, 2048, 1), dtype = "uint8")
Here is how you can use the scipy.ndimage module to rotate your patches:
import numpy as np
import cv2
from random import randrange
from scipy import ndimage
def patch_img(img, patch, amt=5):
h, w, _ = img.shape
for _ in range(amt):
p = ndimage.rotate(patch, randrange(360))
p_h, p_w, _ = p.shape
x = randrange(w - p_w)
y = randrange(h - p_h)
seg = img[y: y + p_h, x: x + p_w]
seg[:] = cv2.bitwise_xor(seg, p)
patch = cv2.imread('imagersult.png')
img = np.zeros((2048, 2048, 3), dtype="uint8")
patch_img(img, patch)
cv2.imshow("Image", img)
cv2.waitKey(0)
Outputs for multiple runs:
For grayscale and variation in size of the patches:
import numpy as np
import cv2
from random import randrange, uniform
from scipy import ndimage
def patch_img(img, patch, amt=5):
h, w = img.shape
min_scale = 0.5
max_scale = 2
for _ in range(amt):
patch_h, patch_w = patch.shape
scale = uniform(min_scale, max_scale)
p = ndimage.rotate(cv2.resize(patch, (int(patch_w * scale), int(patch_h * scale))), randrange(360))
p_h, p_w = p.shape
x = randrange(w - p_w)
y = randrange(h - p_h)
seg = img[y: y + p_h, x: x + p_w]
seg[:] = cv2.bitwise_xor(seg, p)
patch = cv2.imread('imagersult.png', 0)
img = np.zeros((2048, 2048), dtype="uint8")
patch_img(img, patch)
cv2.imshow("Image", img)
cv2.imwrite("result.png", img)
cv2.waitKey(0)
Sample output:
Related
I have some code that gives me an img is not defined error. When I defined image earlier in the code.
What it does is it scans an image and generates a maze out of emojis according to the image. The issue is on the line:
for c in xrange if c < img.shape[1]] for r in yrange if r < img.shape[0]]
Code is below, also I should point out that this is all in a class:
import numpy as np
import cv2
import matplotlib.pyplot as plt
def downloadImage(URL):
"""Downloads the image on the URL, and convers to cv2 RGB format"""
from io import BytesIO
from PIL import Image as PIL_Image
import requests
response = requests.get(URL)
image = PIL_Image.open(BytesIO(response.content))
return cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)
URL = "https://cdn.discordapp.com/attachments/670656848256434176/1001139167159406602/maze2.png"
img = downloadImage(URL)
# Convert ot 2 color
img = cv2.cvtColor(np.array(img), cv2.COLOR_BGR2GRAY)
ret3, th3 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY)
# plt.imshow(th3, cmap='gray')
# Detect corners
CornerKernel = np.ones((3, 3), np.uint8)
corner = cv2.filter2D(th3//255, -1, CornerKernel)
# A corner add up to to 1 or 9
Corners = np.argwhere((corner == 4) | (corner == 8))
antiCorners = np.argwhere((corner == 1) | (corner == 5))
# for each point in Corners, find the closet point in antiCorners
Corner_antiCorner = []
for point in Corners:
distances = np.linalg.norm(antiCorners-point, axis=1)
closest = antiCorners[np.argmin(distances)]
Corner_antiCorner.append((point+closest)/2)
plt.plot([point[1], closest[1]], [point[0], closest[0]], color='r')
# For eachpoint in Corner_antiCorner, find the closet point in Corner_antiCorner
closestCorners = []
for point in Corner_antiCorner:
distances = np.linalg.norm(Corner_antiCorner-point, axis=1)
# closest is itself, so second closest is chosen
closest = Corner_antiCorner[distances.argsort()[1]]
closestCorners.append((point, closest))
plt.plot([point[1], closest[1]], [point[0], closest[0]], color='r')
# Sample of separations dx,dy
dx = np.array([abs(p[1]-q[1]) for p, q in closestCorners])
dy = np.array([abs(p[0]-q[0]) for p, q in closestCorners])
mediandx = np.median(dx[dx > 0])
mediandy = np.median(dy[dy > 0])
print("is this working")
stepY, stepX = int(mediandy), int(mediandx)
xrange = range(stepX//2, img.shape[0], stepX)
yrange = range(stepY//2, img.shape[1], stepY)
x, y = [], []
mazeElement = {0: ':black_large_square:', 1: ':white_large_square:'}
print('for loop 1')
for r in yrange:
for c in xrange:
x.append(c)
y.append(r)
plt.scatter(x, y)
print('for loop 2cd')
self.base_map = [[mazeElement[img[r, c]//255]
for c in xrange if c < img.shape[1]] for r in yrange if r < img.shape[0]]
Can someone tell me how to fix this?
Try removing self. before the assignment self.base_map = . self can only be used inside a class.
I have a static image that I would like to animate to appear like this (except starting from a black image, not a white image):
(image is from this post: Create animated gif from static image)
Here is the code:
import random
import imageio
import numpy as np
from PIL import Image
img = Image.open('/Users/tom/Desktop/sink.jpeg')
pixels = img.load()
width, height = img.size
img2 = Image.new('RGB', img.size, color='black')
pixels2 = img2.load()
coord = []
for x in range(width):
for y in range(height):
coord.append((x, y))
images = []
while coord:
x, y = random.choice(coord)
pixels2[x, y] = pixels[x, y]
coord.remove((x, y))
if len(coord) % 500 == 0:
images.append(np.array(img2))
imageio.mimsave('/Users/tom/Desktop/sink.gif', images)
When I run the code, the script never stops/outputs anything. Anyone know why?
Your code works, it is just very slow. If you are okay with a transparent background you can do something like this:
import numpy as np
import imageio.v3 as iio
rng = np.random.default_rng()
px_per_iter = 1000
img = iio.imread("imageio:chelsea.png")
n_pixels = img.shape[0] * img.shape[1]
batches = int(np.ceil(n_pixels / px_per_iter)) # number of frames
pixels = rng.permutation(n_pixels) # order in which pixels are revealed
frames = np.zeros((batches + 1, *img.shape[:2], 4), dtype=np.uint8)
for batch_idx in range(batches):
idx_batch = pixels[px_per_iter*batch_idx:px_per_iter*(batch_idx+1)]
y_idx, x_idx = np.unravel_index(idx_batch, img.shape[:2])
frame = frames[batch_idx+1]
frame[y_idx, x_idx, :3] = img[y_idx, x_idx]
frame[y_idx, x_idx, 3] = 255 # make added pixels non-transparent
iio.imwrite("fancy.gif", frames, loop=True)
(500kb GIF)
If you need the black background, you can use something like this; however, be aware that it will produce larger files:
import numpy as np
import imageio.v3 as iio
rng = np.random.default_rng()
px_per_iter = 1000
img = iio.imread("imageio:chelsea.png")
n_pixels = img.shape[0] * img.shape[1]
batches = int(np.ceil(n_pixels / px_per_iter)) # number of frames
pixels = rng.permutation(n_pixels) # order in which pixels are revealed
frames = np.zeros((batches + 1, *img.shape), dtype=np.uint8)
for batch_idx in range(batches):
idx_batch = pixels[px_per_iter*batch_idx:px_per_iter*(batch_idx+1)]
y_idx, x_idx = np.unravel_index(idx_batch, img.shape[:2])
frame = frames[batch_idx+1]
frame[:] = frames[batch_idx]
frame[y_idx, x_idx] = img[y_idx, x_idx]
iio.imwrite("fancy.gif", frames)
(result exceeds 2MB, which is SO's limit)
I am using the below code for color-based segmentation using K-means. In this code, each cluster is saving into one image. In my case requirement is a bit different. I want to save only blue color images. Could you please help me how can I save only blue color images?
import numpy as np
import cv2
import pdb
from matplotlib import pyplot as plt
img = cv2.imread('a.png')
Z = np.float32(img.reshape((-1,3)))
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 4
_,labels,centers = cv2.kmeans(Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
labels = labels.reshape((img.shape[:-1]))
reduced = np.uint8(centers)[labels]
result = [np.hstack([img, reduced])]
for i, c in enumerate(centers):
mask = cv2.inRange(labels, i, i)
mask = np.dstack([mask]*3) # Make it 3 channel
ex_img = cv2.bitwise_and(img, mask)
ex_reduced = cv2.bitwise_and(reduced, mask)
result.append(np.hstack([ex_img, ex_reduced]))
pdb.set_trace()
cv2.imwrite('watermelon_out.jpg', np.vstack(result))
Original Image
After using this code I am getting result link below:
Expected Result:
This should only print the blue image. First find the center which is closest to blue color and then plot points only in cluster represented by that center
import numpy as np
import cv2
import pdb
from matplotlib import pyplot as plt
img = cv2.imread('a.png')
Z = np.float32(img.reshape((-1,3)))
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 4
_,labels,centers = cv2.kmeans(Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
labels = labels.reshape((img.shape[:-1]))
reduced = np.uint8(centers)[labels]
blue_dis = 99999999
blue_center = -1
b = (255, 50 , 0)
for i, c in enumerate(centers):
dis = (c[0]-b[0])**2 + (c[1]-b[1])**2 + (c[1]-b[1])**2
if dis < blue_dis:
blue_center = i
blue_dis = dis
result = [np.hstack([img, reduced])]
for i, c in enumerate(centers):
if i!=blue_center:
continue
mask = cv2.inRange(labels, i, i)
mask = np.dstack([mask]*3) # Make it 3 channel
ex_img = cv2.bitwise_and(img, mask)
ex_reduced = cv2.bitwise_and(reduced, mask)
result.append(np.hstack([ex_img, ex_reduced]))
pdb.set_trace()
cv2.imwrite('watermelon_out.jpg', np.vstack(result))
I have written a simple code to add noise to image:
import cv2
from skimage.util import *
img = cv2.imread("./A/0030050944.jpg")
img = random_noise(img, mode='poisson', seed=42, clip=False)
cv2.imwrite("test.jpg", img)
But this only gives a blank black image.
Check this code. It adds gaussian , salt-pepper , poisson and speckle noise in an image.
Parameters
----------
image : ndarray
Input image data. Will be converted to float.
mode : str
One of the following strings, selecting the type of noise to add:
'gauss' Gaussian-distributed additive noise.
'poisson' Poisson-distributed noise generated from the data.
's&p' Replaces random pixels with 0 or 1.
'speckle' Multiplicative noise using out = image + n*image,where
n is uniform noise with specified mean & variance.
import numpy as np
import os
import cv2
def noisy(noise_typ,image):
if noise_typ == "gauss":
row,col,ch= image.shape
mean = 0
var = 0.1
sigma = var**0.5
gauss = np.random.normal(mean,sigma,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy = image + gauss
return noisy
elif noise_typ == "s&p":
row,col,ch = image.shape
s_vs_p = 0.5
amount = 0.004
out = np.copy(image)
# Salt mode
num_salt = np.ceil(amount * image.size * s_vs_p)
coords = [np.random.randint(0, i - 1, int(num_salt))
for i in image.shape]
out[coords] = 1
# Pepper mode
num_pepper = np.ceil(amount* image.size * (1. - s_vs_p))
coords = [np.random.randint(0, i - 1, int(num_pepper))
for i in image.shape]
out[coords] = 0
return out
elif noise_typ == "poisson":
vals = len(np.unique(image))
vals = 2 ** np.ceil(np.log2(vals))
noisy = np.random.poisson(image * vals) / float(vals)
return noisy
elif noise_typ =="speckle":
row,col,ch = image.shape
gauss = np.random.randn(row,col,ch)
gauss = gauss.reshape(row,col,ch)
noisy = image + image * gauss
return noisy
From How to add noise (Gaussian/salt and pepper etc) to image in Python with OpenCV
possion noise
from PIL import Image
import numpy as np
from skimage.util import random_noise
im = Image.open("test.jpg")
# convert PIL Image to ndarray
im_arr = np.asarray(im)
# random_noise() method will convert image in [0, 255] to [0, 1.0],
# inherently it use np.random.normal() to create normal distribution
# and adds the generated noised back to image
noise_img = random_noise(im_arr, mode='possion', var=0.05**2)
noise_img = (255*noise_img).astype(np.uint8)
img = Image.fromarray(noise_img)
img.show()
This is basically the same question that was posted here: How to merge a transparent png image with another image using PIL but using with scikit-image instead of PIL. I mean to paste the png keeping its transparency on top of a background image. Also, if there is actually a way of doing it, I would like to know which one is faster (PIL or scikit-image). Thanks.
Read the two images and add using the formula img1*alpha + img2*(1-alpha)
import numpy as np
from matplotlib import pyplot as plt
import skimage.io
img1 = skimage.io.imread('Desert.jpg')
img2 = skimage.io.imread('Penguins.jpg')
img3 = np.ubyte(0.7*img1 + 0.3*img2)
plt.imshow(img3)
Another option could be to use the alpha channel of two images as masks as below
import numpy as np
from matplotlib import pyplot as plt
import skimage.io
img1 = skimage.io.imread('img1.png')
img2 = skimage.io.imread('img2.png')
mask1 = img1.copy()
mask2 = img2.copy()
mask1[:,:,0] = mask1[:,:,3]
mask1[:,:,1] = mask1[:,:,3]
mask1[:,:,2] = mask1[:,:,3]
mask2[:,:,0] = mask2[:,:,3]
mask2[:,:,1] = mask2[:,:,3]
mask2[:,:,2] = mask2[:,:,3]
img3 = np.bitwise_or(np.bitwise_and(img1, mask1),np.bitwise_and(img2, mask2)) ;
plt.subplot(2,2,1)
plt.imshow(img1)
plt.subplot(2,2,2)
plt.imshow(img2)
plt.subplot(2,2,3)
plt.imshow(img3)
Inspired by user8190410's answer, I built my own function to do it:
from skimage import data
import numpy as np
x, y = 100, 100
background = data.imread('background.jpg') / 255.
image = data.imread('image.png') / 255.
background_height, background_width, background_depth = background.shape
image_height, image_width, image_depth = image.shape
template = np.zeros((background_height, background_width, image_depth))
template[y : y + image_height, x : x + image_width, :] = image
mask = np.stack([template[:,:,3] for _ in range(3)], axis = 2)
inv_mask = 1. - mask
result = background[:,:,:3] * inv_mask + template[:,:,:3] * mask
plt.figure(figsize = (15, 15))
plt.subplot(1, 3, 2)
plt.imshow(image)
plt.subplot(1, 3, 1)
plt.imshow(background)
plt.subplot(1, 3, 3)
plt.imshow(result)
plt.tight_layout()
plt.show()
Please let me know if I can do something to improve computation speed