Pixel extraction with numpy - python

hey i made this little script to cut a picture in 4 (get 4 pic, each a different corner of the source) but the files obtained are 2 with an half of the source and the 2 others are one (thin) strip of the source.
wondering what i got wrong
import numpy as np;
from PIL import Image;
import imageio;
import math;
filename="preview_redd_it-8qwf04k4uc181.jpg"
im_in = Image.open(filename)
img = np.asarray(im_in)
filename=filename.removesuffix(".jpg")
print(img.shape)
shape= img.shape
maxX=math.floor(shape[0]/2)
maxY=math.floor(shape[1]/2)
shape=np.shape((maxX,maxY,shape[2]))
imagesList=[np.zeros(shape),np.zeros(shape),np.zeros(shape),np.zeros(shape)]
for i in range (0,4):
xmin=(i%2)*maxX
xmax=(i%2)*maxX+maxX
ymin=int(i/2)*maxY
ymax=int(i/2)*maxY+maxY
print(str(xmin)+":"+str(xmax))
print(str(ymin)+":"+str(ymax))
print(" ")
imagesList[i]=img[xmin:xmax][ymin:ymax]
imageio.imsave(filename+str(i)+".png",imagesList[i],'jpg')
the ouput:
(sorry for the eye cancer)

If you want the four corners from the mid of each axis then you can use:
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
pil_im = Image.open('lena1.jpg', 'r')
img = np.asarray(pil_im)
plt.imshow(img)
plt.show()
mid_0, mid_1 = img.shape[0]//2, img.shape[1]//2
plt.subplot(2, 2, 1)
plt.imshow(img[0:mid_0, 0:mid_1])
plt.subplot(2, 2, 2)
plt.imshow(img[0:mid_0, mid_1:])
plt.subplot(2, 2, 3)
plt.imshow(img[mid_0:, 0:mid_1])
plt.subplot(2, 2, 4)
plt.imshow(img[mid_0:, mid_1:])
plt.tight_layout()
plt.show()
output:

Related

Keep the original shape of the array as the image

I have some data. I visualize and then save it as image.
import cv2
import numpy as np
import matplotlib.pyplot as plt
data = np.array([
[1,2,0,1],
[0,1,2,1],
[0,0,2,1]])
fig, ax = plt.subplots()
ax.imshow(data)
ax.axis('off')
fig.savefig("test.png", bbox_inches='tight', pad_inches=0)
Next, I load the image and read the shape:
img = cv2.imread('test.png')
print(img.shape)
Output:
(217, 289, 3)
But I want to keep the original resolution and my expected output:
(3, 4, 3)
Any solution?
Upd.:
With dpi=1:
data = np.array([
[1,2,0,1],
[0,1,2,1],
[0,0,2,1],
[1,0,2,1],
[4,1,0,2],
])
fig, ax = plt.subplots()
ax.imshow(data)
ax.axis('off')
fig.savefig("test.png", bbox_inches='tight', pad_inches=0, dpi = 1)
img = cv2.imread('test.png')
img.shape
print(data.shape, img.shape)
Output:
(5, 4)
(3, 2, 3)
Since you're using two different libraries for creating an image and reading the image, it would be difficult to retain the array size as no such information is stored with the image.
The dpi is also specific to your monitor screen and hence is not recommended. Refer to the answer here for more on this.
Also, you're trying to write the image as a 2D array, but when cv2.imread() reads it, it would also consider the color channel and add the third dimension. To avoid this you need to read the image as a grayscale image.
I would suggest that you use cv2.imwrite() to generate the image (works similar to plt.savefig()) and then read the image using cv2.imshow() as a grayscale image.
import cv2
import numpy as np
data = np.array([
[1,2,0,1],
[0,1,2,1],
[0,0,2,1]])
cv2.imwrite("test.png", data)
img = cv2.imread("test.png", 0) #Using 0 to read in grayscale mode
print(data.shape, img.shape)
Output:
(3, 4) (3, 4)
The creation of an image using imshow is totally unnecessary, you can simply compute the matrix of RGBA values that you are interested into
import numpy as np
import matplotlib as mp
data = np.array([ [1,2,0,1],[0,1,2,1],[0,0,2,1]])
n = mp.colors.Normalize(data.min(), data.max())
c = mp.cm.viridis(n(data))[:,:,:-1] # [...,:-1] disregards the alpha values

Is there any faster way to loop through Image in python

program is about removing the gradient background color
Currently it takes about 20 second for single image of size 420X560 size
code is
from colormath.color_objects import sRGBColor, LabColor
from colormath.color_conversions import convert_color
from colormath.color_diff import delta_e_cie2000
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np
import os
import cv2
def backgroundRemovel(url):
img = cv2.imread(url)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.title('original Image')
plt.show()
color=img[0,0]
firstPixelRGB = sRGBColor(color[0], color[1], color[2], is_upscaled=True);
firstPixelLab = convert_color(firstPixelRGB, LabColor);
t=img.shape
x_dim=t[0]
y_dim=t[1]
for i in range(x_dim):
for j in range(y_dim):
rgbCurPixel=img[i,j]
curPixelRGB=sRGBColor(rgbCurPixel[0], rgbCurPixel[1], rgbCurPixel[2], is_upscaled=True);
curPixelLab=convert_color(curPixelRGB, LabColor);
delta_e = delta_e_cie2000(firstPixelLab, curPixelLab);
#print("difference is "+str(delta_e))
if delta_e<15:
img[i, j] = (0, 0, 0)
return img
fnmae="image.jpeg"
open_cv_image = backgroundRemovel(fname)
plt.imshow(open_cv_image)
plt.title('Background Removed Image')
plt.show()
Input Image:
Desired:
if there is any better way to remove gradient background of image please do share

Using imshow methods in a for loop to print multiple images

I have a simple 2d numpy array which is a pixel map of a gray scale image. I am trying to print some parts of the image. My code is
from google.colab import drive
drive.mount('/content/drive')
import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread('/content/drive/My Drive/Colab Notebooks/sample2.jpg') # the source file is correctly mounted
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
And
i = 0
while i < (len(roi) - 1): # roi is a list of strictly increasing positive integers
print(roi[i], roi[i+1])
plt.imshow(img_gray[roi[i]:roi[i+1]], cmap='gray')
i += 1
For example if roi = [10, 40, 50, 100], it should prints two parts of the image. But as I run the cell above, it only print one image which is the last part of the image. Is it possible not to overwrite other image and print them all?
You should try calling plt.show() after each plt.imshow(...):
i = 0
while i < (len(roi) - 1): # roi is a list of strictly increasing positive integers
print(roi[i], roi[i+1])
plt.imshow(img_gray[roi[i]:roi[i+1]], cmap='gray')
plt.show() # <----- this will show all plots
i += 1
Or, if you want to keep a nicer, more organized plot, you could use subplots, although you should state how many subplots you want, here is an example with random input:
import matplotlib.pyplot as plt
import numpy as np
ims = np.random.randn(3, 224, 224)
fig, ax = plt.subplots(1, 3)
for i in range(3):
ax[i].imshow(ims[i])
This last example will plot the images arranged horizontally:

What is the difference between PIL's and OpenCV's resize

I came over the following issue: the resize functions of these two libraries behave differently. Here is a small test:
import numpy as np
import PIL
import cv2
from matplotlib import pyplot as plt
img = np.random.randn(10, 10, 3)
SIZE = (5, 5)
img -= img.min()
img /= img.max()
img = (img*255).astype(np.uint8)
# Display the initial image
plt.figure(figsize=(16,9))
plt.imshow(img)
plt.show()
plt.close()
# resize the image in two different ways
img_cv2 = cv2.resize(img, dsize=SIZE, interpolation=cv2.INTER_LINEAR)
img_pil = PIL.Image.fromarray(img).resize(SIZE, resample=PIL.Image.BILINEAR)
# get the difference image and normalize it
diff = np.abs(img_cv2.astype(np.float32) - img_pil)
diff /= diff.max() or 1
# display results
fig, axs = plt.subplots(1, 3, figsize=(16, 9))
axs[0].imshow(img_cv2)
axs[1].imshow(img_pil)
axs[2].imshow(diff)
plt.show()
plt.close()
My question is now: why is this happening? Is the difference in the implementation (I didn't check the code in PIL or OpenCV yet) or am I using the functions in the wrong way?
Here are some example outputs: Input image and Resized images.

Add noise to RGB image in python

I need to add noise to multiple of coloured images (file format is ppm; source: http://benchmark.ini.rub.de/Dataset/GTSRB_Final_Training_Images.zip) in python. The noised output images should be still in colour.
I tryed the following:
from scipy import misc
import numpy as np
import cv2
import imageio
# Read image ('00000_00030.ppm') from file system
image = misc.imread('./00000/00000_00030.ppm', mode="RGB")
# Add noise to the input image
noised_image = image + 3 * image.std() * np.random.random(image.shape)
# Plot original and noisy images
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(image)
axarr[0, 0].set_title('Original image')
axarr[0, 1].imshow(noised_image)
axarr[0, 1].set_title('Noised image')
plt.show()
# Save noised image to file system
saved_image = cv2.imwrite("./noised.ppm", noised_image)
But first of all the problem is that the noised image won't be plotted correctly in jupyter notebook (see figure 1):
figure 1
The second problem is that the RG-channels (Red and Green) were be lost (in saved file):
figure 2
So how can I preserve all RGB colors in noised image?
After searching for a long time I have the solution now - the saved file preserves now all RGB-colours (See Line 8 in following code; see figure 3):
from scipy import misc
import numpy as np
import cv2
import imageio
# Read image ('00000_00030.ppm') from file system
# image = misc.imread('./00000/00000_00030.ppm', mode="RGB")
image = cv2.imread('./00000/00000_00030.ppm',1)
# Add noise to the input image
noised_image = image + 3 * image.std() * np.random.random(image.shape)
# Plot original and noisy images
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(image)
axarr[0, 0].set_title('Original image')
axarr[0, 1].imshow(noised_image)
axarr[0, 1].set_title('Noised image')
plt.show()
# Save noised image to file system
saved_image = cv2.imwrite("./noised1.ppm", noised_image)
Figure 3
But the plotted figures are still wrong:
Figure 4
Here is the final Code to add noise to RGB images in python, and plot them correctly:
from scipy import misc
import numpy as np
import cv2
import imageio
# Read image ('00000_00030.ppm') from file system
# image = misc.imread('./00000/00000_00030.ppm', mode="RGB")
image = cv2.imread('./00000/00000_00030.ppm',1)
# Add noise to the input image
noised_image = image + 3 * image.std() * np.random.random(image.shape)
RGB_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Plot original and noisy images
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(RGB_image)
axarr[0, 0].set_title('Original image')
axarr[0, 1].imshow(noised_image)
axarr[0, 1].set_title('Noised image')
plt.show()
# Save noised image to file system
saved_image = cv2.imwrite("./noised1.ppm", noised_image)
This will take the pixel values of the given image and start encoding the noise that you give as input to the least significant bits in the pixel. The image output would vary slightly.
def asciiToBin(ascii):
return ''.join(str(bin(ord(byte)))[2:].zfill(8) for byte in ascii)
def hide(img, data, outName):
dataBin = asciiToBin(data)
pixels, mode = list(img.getdata()), img.mode
newPixels = []
for i in range(len(dataBin)):
newPixel = list(pixels[i])
newPixel[i%len(mode)] = setLSB(newPixel[i%len(mode)], dataBin[i])
newPixels.append(tuple(newPixel))
newData = newPixels + pixels[len(newPixels):]
img.putdata(newData)
img.save(outName, "PNG")
def setLSB(target, value):
binary = str(bin(target))[2:]
if binary[-1] != value:
binary = binary[:-1] + value
return int(binary, 2)

Categories

Resources