I am trying to complete a challenge where i use an equation to construct a new image (d) from other images. Then i must get the flag in the image (d). The given images are a.png, b.png c.png and y.png and they can be found here: https://drive.google.com/drive/folders/1bZOm_0apr5ZmaRNf9R5UVIEmtMuYSphn?usp=sharing
The equation: d = y - 21a - 3b + 41c
My current code
from PIL import Image
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
size = width, height = imagey.size
new = Image.new('RGB', size)
imgy = imagey.load()
imga = imagea.load()
imgb = imageb.load()
imgc = imagec.load()
data = new.load()
for x in range(width):
for y in range(height):
they = imgy[x, y]
thea = imga[x, y]
theb = imgb[x, y]
thec = imgc[x, y]
new_color = ((int(they[0])) & ~(int((21 * thea[0])) ^ int((3 * theb[0])) ^ int(~(41 * thec[0]))),
(int(they[1])) & ~(int((21 * thea[1])) ^ int((3 * theb[1])) ^ int(~(41 * thec[1]))),
(int(they[2])) & ~(int((21 * thea[2])) ^ int((3 * theb[2])) ^ int(~(41 * thec[2]))))
data[x, y] = new_color
new.save('final.png')
new.show()
If you would convert Pillow image to numpy array or you would use OpenCV or imageio to load image (and get directly numpy array) then you could do
directly
new = imagey - 21*imagea - 3*imageb + 41*imagec
Result:
Not ideal but much better than with your code.
It can be problem with overflow. It may create array with 8bits values and calculations can gives 16bits or 32bits values which can be reduced to 8bits in every calculation.
Full working code:
import imageio
imagey = imageio.imread('y.png')
imagea = imageio.imread('a.png')
imageb = imageio.imread('b.png')
imagec = imageio.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
imageio.imwrite('final.png', new)
# --- imageio doesn't have function to display it ---
import matplotlib.pyplot as plt
plt.imshow(new)
plt.show()
EDIT:
If I use OpenCV then I get ideal result
Full working code:
import cv2
imagey = cv2.imread('y.png')
imagea = cv2.imread('a.png')
imageb = cv2.imread('b.png')
imagec = cv2.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
cv2.imwrite('final.png', new)
# --- show window with image and wait for press any key ---
cv2.imshow('Image', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT:
By the way: version which converts PIL Image to numpy array and later it converts back to PIL Image - but it gives the same result as imageio.
from PIL import Image
import numpy as np
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
arr_y = np.array(imagey)
arr_a = np.array(imagea)
arr_b = np.array(imageb)
arr_c = np.array(imagec)
arr_new = arr_y - 21*arr_a - 3*arr_b + 41*arr_c
new = Image.fromarray(arr_new)
new.save('final.png')
new.show()
BTW:
If I check images on Linux using program file then it shows that b.png and c.png are JPEG, not PNG.
$ file b.png
b.png: JPEG image data, JFIF standard 1.01, resolution (DPI),
density 300x300, segment length 16,
Exif Standard: [TIFF image data, big-endian, direntries=0], baseline,
precision 8, 960x640, components 3
I found that cv2.imread() gives little different values for c.png(which is JPG file) then other modules - and I don't mean that cv2 gives colors in BGR instead of RGB - and later this gives correct result. Probably cv2 uses different C library to read JPG.
Related
im working with a hamamatsu camera, I get a NumPy array and I want to save the array like an image, I can do it to a TIF image but i don't know how to convert the TIF image or the array to get a correct jpg image, I have this code:
img = Image.fromarray(self.val_fin)
if int(self.vTIFF.get()) == 1:
imgTIFF = img.convert('I')
img.save('name1.tiff')
if int(self.vJPG.get()) == 1:
imgJPG = img.convert('RGB')
imgJPG.save('name2.jpg')
Where val_fin is a 32bit array whose negative values have been changed to 0, the result of the jpg image is a black image.
Thanks.
using tiff 32bites float image:
I can run this code:
from PIL import Image
import numpy as np
def normalize8(I):
mn = I.min()
mx = I.max()
mx -= mn
I = ((I - mn)/mx) * 255.0
return np.round(I).astype(np.uint8)
img1 = Image.open('test_fl.tif', 'r')
arr = np.asarray(img1)
print(arr.size, arr.shape, arr.ndim , arr.dtype)
img = Image.fromarray(arr, mode='F')
print(img.size, img.format, img.mode)
img.save('test_saved.tif')
# doesnt work
# imgTIFF = img.convert(mode='I')
# imgTIFF.save('name1.tif')
# img2 = Image.open('name1.tif', 'r')
# print(img2.size, img2.format, img2.mode)
imgTIFF = Image.fromarray(normalize8(arr))
imgTIFF.save('name1.tif')
img2 = Image.open('name1.tif', 'r')
print(img2.size, img2.format, img2.mode)
imgJPG = imgTIFF.convert('RGB')
imgJPG.save('name2.jpg')
img3 = Image.open('name2.jpg')
print(img3.size, img3.format, img3.mode)
img3.show()
print(img3.getpixel((0,0)))
taken from How should I convert a float32 image to an uint8 image?
the imgTIFF = img.convert(mode='I')
trying to convert tiff 32float to 32int gives a black Image to me too
Can I use cv2 or numpy to turn an image into a negative? Something like below but I need to edit still.
My question is mainly the top bit of code if I can use that to invert the grayscale and black&white both to a negative?
import cv2
import numpy as np
img = cv2.imageread('imagename.jpg')
print(img.dtype)
image_neg = 255 - img
cv2.imshow('negative',image_neg)
cv2.waitKey(0)
#######################################
from images import Image
def invert(image):
def blackAndWhite(image):
blackPixel = (0, 0, 0)
whitePixel = (255, 255, 255)
for y in range(image.getHeight()):
for x in range(image.getWidth()):
(r, g, b) = image.getPixel(x, y)
average = (r + g + b) // 3
if average < 128:
image.setPixel(x, y, blackPixel)
else:
image.setPixel(x, y, whitePixel)
def grayscale(image):
for y in range(image.getHeight()):
for x in range(image.getWidth()):
(r, g, b) = image.getPixel(x, y)
r = int(r * 0.299)
g = int(g * 0.587)
b = int(b * 0.114)
lum = r + g + b
image.setPixel(x, y, (lum, lum, lum))
def main():
filename = input("Enter the image file name: ")
image = Image(filename)
#Invert image
invert(image)
image.draw()
#Covert to greyscale, then invert
"""grayscale(image)
invert(image)
image.draw()"""
#Convert to black and white, then invert
"""blackAndWhite(image)
invert(image)
image.draw()"""
if __name__ == "__main__":
main()
I receive the following error:
Traceback (most recent call last):
File "invert.py", line 14, in <module>
image_neg = 255 - image
NameError: name 'image' is not defined
I changed the code in the beginning to say this:
import cv2
import numpy as np
image = cv2.imageread('smokey.gif')
print(image.dtype)
image_neg = 255 - image
cv2.imshow('negative',image_neg)
cv2.waitKey(0)
Well I thought this would work but it tells me line - "invertedImage = cv2.bitwise_not(imageToInvert)" has a SyntaxError: invalid non-printable character U+00A0
I edited my code correctly on here (4 spaces) and I have no clue why it's not showing correctly still.
from images import Image
import cv2
def invert(image):
imageToInvert = cv2.imread(filepath)
invertedImage = cv2.bitwise_not(imageToInvert)
cv2.imgwrite("BWimage.png",invertedImage)
print("inverted image saved")
File_path='smokey.gif'
invert(File_path)
Not sure what error you are getting. Maybe something here will help?
Syntax: cv2.cv.flip(src, flipCode[, dst] )
Parameters:
src: Input array.
dst: Output array of the same size and type as src.
flip code: A flag to specify how to flip the array; 0 means flipping around the x-axis and positive value (for example, 1) means flipping around y-axis. Negative value (for example, -1) means flipping around both axes.
Return Value: It returns an image.
As found in OpenCV
example code:
# Python program to explain cv2.flip() method
# importing cv2
import cv2
# path
path = r'C:\Users\user\Desktop\geeks14.png'
# Reading an image in default mode
src = cv2.imread(path)
# Window name in which image is displayed
window_name = 'Image'
# Using cv2.flip() method
# Use Flip code 0 to flip vertically
image = cv2.flip(src, 0)
# Displaying the image
cv2.imshow(window_name, image)
cv2.waitKey(0)
I am using two different ways to re-size an image, but all three look exactly the same...
What am I doing wrong that no scaling occurs?
import cv2 as cv
import numpy as np
path = "resources/Shapes.png"
img = cv.imread(path)
cv.imshow("img", img)
res1 = cv.resize(img, None, fx = 2, fy = 2, interpolation = cv.INTER_CUBIC)
cv.imshow("res1", res1)
height, width = img.shape[:2]
res2 = cv.resize(img, (2 * width, 2 * height), interpolation = cv.INTER_CUBIC)
cv.imshow("res2", res2)
k = cv.waitKey(0)
Just putting this here for future reference:
The code above works, the issue was that imshow does not always show the true size of the image, by saving the different images, or simply examining them with res1.shape vs img.shape, you can see the true size of the image.
This question already has an answer here:
How do you divide an image/array into blocks?
(1 answer)
Closed 2 years ago.
I have a Numpy Array type image which I would like to split into 9 (3 x 3) even tiles which I can iterate over. How can I do this?
Here is my code so far to generate the numpy.ndarray but I haven't managed to split it:
The numpy image array to split is th1
import cv2
import numpy as np
# Only for the threshold display
from matplotlib import pyplot as plt
# The Image to be used
image = 'six.png'
# Finding the average greyscale value
image_bgr = cv2.imread(image, cv2.IMREAD_COLOR)
# Calculate the mean of each channel
channels = cv2.mean(image_bgr)
# Type Float
thresh = channels[0]/2
#print (thresh)
# Displaying the threshold value
img = cv2.imread(image,0)
img = cv2.medianBlur(img,5)
# If below then black else white
ret,th1 = cv2.threshold(img,thresh,255,cv2.THRESH_BINARY)
titles = ['Original Image', 'Global Thresholding']
images = [img, th1, ret]
for i in range(2):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
# Shows single image on its' own
plt.imshow(images[1], 'gray')
plt.xticks([]),plt.yticks([])
Here is the image (six.png):
What I would do is create a list or a 2-dimensional array in which I'd save the "tiles" of the full image. The tiles would be copied using the code below:
height, width, dim = img.shape
image_tile = img[0:height/3, 0:width/3]
It creates a new ndarray image_tile that contains the part of the full image array that's inside of the coordinates. In this case it is the top left tile.
The whole example with a for loop would look something like this:
image_tile = []
for i in range(0,3):
for j in range(0,3):
image_tile.append(img[i * height/3:(i+1) * height/3, j * width/3:(j+1) * width/3])
I hope this helps and good luck!
I have found a solution adapted from elsewhere and it works great!
img = th1
numrows, numcols = 3, 3
height = int(img.shape[0] / numrows)
width = int(img.shape[1] / numcols)
for row in range(numrows):
for col in range(numcols):
y0 = row * height
y1 = y0 + height
x0 = col * width
x1 = x0 + width
individual = (img[y0:y1, x0:x1])
plt.imshow(individual, 'gray')
plt.xticks([]),plt.yticks([])
plt.show()
I want to apply a pinch/bulge filter on an image using Python OpenCV. The result should be some kind of this example:
https://pixijs.io/pixi-filters/tools/screenshots/dist/bulge-pinch.gif
I've read the following stackoverflow post that should be the correct formula for the filter: Formulas for Barrel/Pincushion distortion
But I'm struggling to implement this in Python OpenCV.
I've read about maps to apply filter on an image: Distortion effect using OpenCv-python
As for my understanding, the code could look something like this:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# set up the x and y maps as float32
flex_x = np.zeros((h, w), np.float32)
flex_y = np.zeros((h, w), np.float32)
# create map with the barrel pincushion distortion formula
for y in range(h):
for x in range(w):
flex_x[y, x] = APPLY FORMULA TO X
flex_y[y, x] = APPLY FORMULA TO Y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
Is this the correct way to achieve the distortion presented in the example image? Any help regarding useful ressources or preferably examples are much appreciated.
After familiarizing myself with the ImageMagick source code, I've found a way to apply the formula for distortion. With the help of the OpenCV remap function, this is a way to distort an image:
import numpy as np
import cv2 as cv
f_img = 'example.jpg'
im_cv = cv.imread(f_img)
# grab the dimensions of the image
(h, w, _) = im_cv.shape
# set up the x and y maps as float32
flex_x = np.zeros((h, w), np.float32)
flex_y = np.zeros((h, w), np.float32)
# create map with the barrel pincushion distortion formula
for y in range(h):
delta_y = scale_y * (y - center_y)
for x in range(w):
# determine if pixel is within an ellipse
delta_x = scale_x * (x - center_x)
distance = delta_x * delta_x + delta_y * delta_y
if distance >= (radius * radius):
flex_x[y, x] = x
flex_y[y, x] = y
else:
factor = 1.0
if distance > 0.0:
factor = math.pow(math.sin(math.pi * math.sqrt(distance) / radius / 2), -amount)
flex_x[y, x] = factor * delta_x / scale_x + center_x
flex_y[y, x] = factor * delta_y / scale_y + center_y
# do the remap this is where the magic happens
dst = cv.remap(im_cv, flex_x, flex_y, cv.INTER_LINEAR)
cv.imshow('src', im_cv)
cv.imshow('dst', dst)
cv.waitKey(0)
cv.destroyAllWindows()
This has the same effect as using the convert -implode function from ImageMagick.
You can do that using implode and explode options in Python Wand, which uses ImageMagick.
Input:
from wand.image import Image
import numpy as np
import cv2
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(0.5)
img.save(filename='zelda1_implode.jpg')
# convert to opencv/numpy array format
img_implode_opencv = np.array(img)
img_implode_opencv = cv2.cvtColor(img_implode_opencv, cv2.COLOR_RGB2BGR)
with Image(filename='zelda1.jpg') as img:
img.virtual_pixel = 'black'
img.implode(-0.5 )
img.save(filename='zelda1_explode.jpg')
# convert to opencv/numpy array format
img_explode_opencv = np.array(img)
img_explode_opencv = cv2.cvtColor(img_explode_opencv, cv2.COLOR_RGB2BGR)
# display result with opencv
cv2.imshow("IMPLODE", img_implode_opencv)
cv2.imshow("EXPLODE", img_explode_opencv)
cv2.waitKey(0)
Implode:
Explode: