iterating through two image arrays to create merged image - python

I have two 128x128 black and white images, black background and white image in centre of image. One is an input into another function and the output is the output of this function. I need to take the bottom right 64x64 pixels of the output image and compare them to the bottom right 64x64 of the input image array. Where a pixel is white in the output I need the corresponding pixel in the input to be made white also.
I have tried just using numpy slicing to cut and paste the 64x64 part of the output over the input but occasionally the input is larger than the output so this is not desirable.
I've tried looping through a single image with the following type of looping code:
for (i,row) in enumerate(image_mesh):
for (j,pixel) in enumerate(row):
print(pixel)
But am stuck on how to loop through two arrays simultaneously and compare individual pixels. Sample images attached.

Assuming your images are RGB and you are trying to compare black (0, 0, 0) against white (1, 1, 1)
You can simply compare them
comparison_ab = np.allclose(img_a[64:, 64:, :], img_b[64:, 64:, :]) # 64x64 bool
and create an RGB image out of it using broadcasting
comparison_ab * np.array([1, 1, 1])[None, None, :] # 64x64x3 float
or take the elementwise minimum
np.minimum(img_a, img_b)

Couldn't get Nil's answer to work but resolved it using:
#convert input files to bool
img_a=input > 200
img_b=output[:,:,0] > 200
comparison = img_b>img_a
#convert from bool to uint8
comparison=comparison.astype('uint8')*255
Converting to a bool array was helpful, a direct greater than operation separated out the differences nicely. I was able to paste this in with a slicing operation easily.

Related

Cropping ROI regions in an numpy array

I am writing some codes to cut two seprate ROI regions in an numpy array. The array is a mask array with boolean values and it consists of two major left and right parts.
I need to crops those left and right parts from my original numpy array. My codes are as follow which are a section of function (image and masked are passed to this function)
if mask.shape[-1] > 0:
# We're treating all instances as one, so collapse the mask into one layer
mask = (np.sum(mask, -1, keepdims=True) >= 1)
zeros=np.zeros(image.shape)
#splash = np.where(mask, image, gray).astype(np.uint8)
splash = np.where(mask, image, zeros).astype(np.uint8)
I am not sure how to achieve this as I am really new to bumpy. I can splash the imge but what I need is differt I ned to crop two left and right parts and for this I need to crop or reshape the mask array. I have attached a splashed output sample to this thread
This is a very typical problem in computer vision. One popular solution to this is the Connected Component Labeling (or CCL). OpenCV has already an implementation for this:
https://docs.opencv.org/3.4/d3/dc0/group__imgproc__shape.html#gaedef8c7340499ca391d459122e51bef5
Then you may use blob analysis to crop out the objects:
https://docs.opencv.org/3.4/d0/d7a/classcv_1_1SimpleBlobDetector.html

Replace certain pixels by integers in numpy array

I have made myself a numpy array from a picture using
from PIL import Image
import numpy as np
image = Image.open(file)
np.array(image)
its shape is (6000, 6000, 4) and in that array I would like to replace pixel values by one number lets say this green pixel [99,214,104,255] will be 1.
I have only 4 such pixels I want to replace with a number and all other pixels will be 0. Is there a fast and efficient way to do so and what is the best way to minimize the size of the data. Is it better to save it as dict(), where keys will be x,y and values, will be integers? Or is it better to save the whole array as it is with the shape it has? I only need the color values the rest is not important for me.
I need to process such a picture as fast as possible because there is one picture every 5 minutes and lets say i would like to store 1 year of data. That is why I'd like to make it as efficient as possible time and space-wise.
If I understand the question correctly, you can use np.where for this:
>>> arr = np.array(image)
>>> COLOR = [99,214,104,255]
>>> np.where(np.all(arr == COLOR, axis=-1), 1, 0)
This will produce a 6000*6000 array with 1 if the pixel is the selected colour, or 0 if not.
How about just storing in a database: the position and value of the pixels you want to modify, the shape of the image, the dtype of the array and the extension (jpg, etc...). You can use that information to build a new image from an array filled with 0.

Convert Canny edge detection into np.array

I have written a function where I want to detect the edges of an image using the Canny algorithm. I then want to extract the 2d array of this image, and then flatten it into a 1d array.
def canny_detection(image):
# Convert to grayscale and convert the image to float
RGB = img_as_float(color.rgb2gray(image))
# Apply Canny edge detection algorithm
edge_canny = feature.canny(RGB, 3).astype(int)
#Get output array
canny_arr = np.array(edge_canny)
# Flatten output array
canny_flat = canny_arr.flatten()
return canny_flat
However, when I call the function with an example image, the output is just a huge array of 0s. I'm sure that's not right. I've tested the canny algorithm on the image, and the resulting image is correct. But the problem is when I want to get the vector of the image.
Can anyone help with this?
I suspect problem might be in that line:
edge_canny = feature.canny(RGB, 3).astype(int)
please replace it with
edge_canny = feature.canny(RGB, 3)
print(edge_canny)
edge_canny = edge_canny.astype(int)
print(edge_canny)
and check what it prints, if first is some nonzero float values <1.0 and second is 0s, that probably means that feature.canny produces values from 0.0 to 1.0 and then you lose it converting to int.
EDIT: Fixed my code.

Check if cifar10 is converted well

Recently I followed a few tutorials on machine learning, and now I want to test if I can make some image recognition program by myself. For this I want to use the CIFAR 10 dataset, but I think I have a small problem in the conversion of the dataset.
For who is not familiar with this set: the dataset comes as lists of n rows and 3072 columns, in which the first 1024 columns represent the red values, the second 1024 the green values and the last are the blue values. Each row is a single image (size 32x32) and the pixel rows are stacked after each other (first 32 values are the red values for the top-most row of pixels, etc.)
What I wanted to do with this dataset is to transform it to a 4D tensor (with numpy), so I can view the images with matplotlibs .imshow(). the tensor I made has this shape: (n, 32, 32, 3), so the first 'dimension' stores all images, the second stores rows of pixels, the third stores individual pixels and the last represents the rgb values of those pixels. Here is the function I made that should do this:
def rawToRgb(data):
length = data.shape[0]
# convert to flat img array with rgb pixels
newAr = np.zeros([length, 1024, 3])
for img in range(length):
for pixel in range(1024):
newAr[img, pixel, 0] = data[img, pixel]
newAr[img, pixel, 1] = data[img, pixel+1024]
newAr[img, pixel, 2] = data[img, pixel+2048]
# convert to 2D img array
newAr2D = newAr.reshape([length, 32, 32, 3])
# plt.imshow(newAr2D[5998])
# plt.show()
return newAr2D
Which takes a single parameter (a tensor of shape (n, 3072)). I have commented out the pyplot code, as this is only for testing, but when testing, I noticed that everything seems to be ok (I can recognise the shapes of the objects in the images, but I am not sure if the colours are good or not, as I get some oddly-coloured images as well as some pretty normal images... Here are a few examples: purple plane, blue cat, normal horse, blue frog.
Can anyone tell me wether I am making a mistake or not?
The images that appear oddly-coloured are the negative of the actual image, so you need to subtract each pixel value from 255 to get the true value. If you simply want to see what the original images look like, use:
from scipy.misc import imread
import matplotlib.pyplot as plt
img = imread(file_path)
plt.imshow(255 - img)
plt.show()
The original cause of the problem is that the CIFAR-10 data stores the pixel values on a scale of 0-255, but matplotlib's imshow() method (which I assume you are using) expects inputs between 0 and 1. Given an input that is not scaled between 0 and 1, imshow() does some normalization internally, which causes some images to become negatives.

How to get border pixels of an image in python?

I have an image, using steganography I want to save the data in border pixels only.
In other words, I want to save data only in the least significant bits(LSB) of border pixels of an image.
Is there any way to get border pixels to store data( max 15 characters text) in the border pixels?
Plz, help me out...
OBTAINING BORDER PIXELS:
Masking operations are one of many ways to obtain the border pixels of an image. The code would be as follows:
a= cv2.imread('cal1.jpg')
bw = 20 //width of border required
mask = np.ones(a.shape[:2], dtype = "uint8")
cv2.rectangle(mask, (bw,bw),(a.shape[1]-bw,a.shape[0]-bw), 0, -1)
output = cv2.bitwise_and(a, a, mask = mask)
cv2.imshow('out', output)
cv2.waitKey(5000)
After I get an array of ones with the same dimension as the input image, I use cv2.rectangle function to draw a rectangle of zeros. The first argument is the image you want to draw on, second argument is start (x,y) point and the third argument is the end (x,y) point. Fourth argument is the color and '-1' represents the thickness of rectangle drawn (-1 fills the rectangle). You can find the documentation for the function here.
Now that we have our mask, you can use 'cv2.bitwise_and' (documentation) function to perform AND operation on the pixels. Basically what happens is, the pixels that are AND with '1' pixels in the mask, retain their pixel values. Pixels that are AND with '0' pixels in the mask are made 0. This way you will have the output as follows:
.
The input image was :
You have the border pixels now!
Using LSB planes to store your info is not a good idea. It makes sense when you think about it. A simple lossy compression would affect most of your hidden data. Saving your image as JPEG would result in loss of info or severe affected info. If you want to still try LSB, look into bit-plane slicing. Through bit-plane slicing, you basically obtain bit planes (from MSB to LSB) of the image. (image from researchgate.net)
I have done it in Matlab and not quite sure about doing it in python. In Matlab,
the function, 'bitget(image, 1)', returns the LSB of the image. I found a question on bit-plane slicing using python here. Though unanswered, you might want to look into the posted code.
To access border pixel and enter data into it.
A shape of an image is accessed by t= img.shape. It returns a tuple of the number of rows, columns, and channels.A component is RGB which 1,2,3 respectively.int(r[0]) is variable in which a value is stored.
import cv2
img = cv2.imread('xyz.png')
t = img.shape
print(t)
component = 2
img.itemset((0,0,component),int(r[0]))
img.itemset((0,t[1]-1,component),int(r[1]))
img.itemset((t[0]-1,0,component),int(r[2]))
img.itemset((t[0]-1,t[1]-1,component),int(r[3]))
print(img.item(0,0,component))
print(img.item(0,t[1]-1,component))
print(img.item(t[0]-1,0,component))
print(img.item(t[0]-1,t[1]-1,component))
cv2.imwrite('output.png',img)

Categories