Encrypt then decrypt pixels bits of image - python

I want to encrypt an image by its bits (010101) of 128 length (i have to perform an algorithm on it), then save the new image.
And read the encrypted image, then reverse back the bits and then save it again.
I have tried several methods:
base64 encode/decode: it works but the encrypted images is not viewable (corrupted header), but when I decrypt it, it back to normal again.
By using PIL library: reading the image data, change the pixel value, then created new image (image is viewable - one requirement is completed), but when I decrypt it, it is not coming back to its previous state.
example with PIL putpixel:
def enc(original_name, encrypted_name):
input_image = Image.open(original_name)
data = input_image.load()
output_image = Image.new(input_image.mode, input_image.size)
for x in range(input_image.size[0]):
for y in range(input_image.size[1]):
r, g, b = data[x, y]
r1 = int('{:08b}'.format(r)[::-1], 2)
g1 = int('{:08b}'.format(g)[::-1], 2)
b1 = int('{:08b}'.format(b)[::-1], 2)
output_image.putpixel((x, y), (r1, g1, b1))
output_image.save(encrypted_name)
input_image.close()
output_image.close()
def dec(encrypted_name, original_name):
encrypted_image = Image.open(encrypted_name)
data = encrypted_image.load()
normal_image = Image.new(encrypted_image.mode, encrypted_image.size)
for x in range(encrypted_image.size[0]):
for y in range(encrypted_image.size[1]):
r, g, b = data[x, y]
r1 = int('{:08b}'.format(r)[::-1], 2)
g1 = int('{:08b}'.format(g)[::-1], 2)
b1 = int('{:08b}'.format(b)[::-1], 2)
normal_image.putpixel((x, y), (r1, g1, b1))
normal_image.save(original_name)
encrypted_image.close()
normal_image.close()
enc('images/lena.jpg', 'images/lena-enc.jpg')
dec('images/lena-enc.jpg', 'images/lena-dec.jpg')
example with putdata:
def enc(original_name, encrypted_name):
original_image = Image.open(original_name)
encrypted_image = Image.new(original_image.mode, original_image.size)
raw = list(original_image.getdata())
eraw = []
for px in raw:
r, g, b = px
r1 = int('{:08b}'.format(r)[::-1], 2)
g1 = int('{:08b}'.format(g)[::-1], 2)
b1 = int('{:08b}'.format(b)[::-1], 2)
eraw.append((r1, g1, b1))
encrypted_image.putdata(eraw)
encrypted_image.save(encrypted_name)
original_image.close()
encrypted_image.close()
def dec(encrypted_name, original_name):
encrypted_image = Image.open(encrypted_name)
raw = list(encrypted_image.getdata())
normal_image = Image.new(encrypted_image.mode, encrypted_image.size)
eraw = []
for px in raw:
r, g, b = px
r1 = int('{:08b}'.format(r)[::-1], 2)
g1 = int('{:08b}'.format(g)[::-1], 2)
b1 = int('{:08b}'.format(b)[::-1], 2)
eraw.append((r1, g1, b1))
normal_image.putdata(eraw)
normal_image.save(original_name)
encrypted_image.close()
normal_image.close()
enc('images/lena.jpg', 'images/lena1.jpg')
dec('images/lena1.jpg', 'images/lena2.jpg')
Is there any way to get the viewable encrypted image that can be decrypted?

Related

TypeError: Image data of dtype object cannot be converted to float when normalizing RGB channel of images

i try to change the value of RGB channel with this function i created
def color_norm(image_norm):
pixels = np.array(image_norm)
ar_mean = np.mean(pixels, axis=(0,1))
(H,W) = image_norm.shape[:2]
for x in range(H):
for y in range(W):
Ri = image_norm[:,:,0]
Gi = image_norm[:,:,1]
Bi = image_norm[:,:,2]
R = Ri[x,y] = np.min((Ri[x,y]/(ar_mean[0]))*(r))
if R > 255:
# saturate value
R = 255
else:
# add normally
R = R
G = Gi[x,y] = np.min((Gi[x,y]/(ar_mean[1]))*(g))
if G > 255:
# saturate value
G = 255
else:
# add normally
G = G
B = Bi[x,y] = np.min((Bi[x,y]/(ar_mean[2]))*(b))
if B > 255:
# saturate value
B = 255
else:
# add normally
B = B
image_norm[x,y] = [R,G,B]
But when I applied this function on my dataset like this
f, axes = plt.subplots(nrows=2, ncols=4, figsize=(20,10))
axes = axes.ravel()
for i, images in enumerate(test_dataset):
images1 = crop_img(images)
images2 = cv2.resize(images1, (512,512))
images3 = color_norm(images2)
axes[i].imshow(images)
axes[i+4].imshow(images3)
plt.tight_layout()
Suddenly it got an error TypeError: Image data of dtype object cannot be converted to float
anyone can help?
I try to change the input image but that doesn't work, or anyone know how to stack the RGB channel again instead using like in my code?

Combine two normal texture maps with python cv2

I'm wanting to combine two normal texture maps. My understanding is one of the simplest methods is sum the red/green channels from each normal map and then divide by the length.
Reference a concept from here as well and trying to convert to python: https://blog.selfshadow.com/publications/blending-in-detail/ (the simpler UDN blending method)
float3 r = normalize(float3(n1.xy + n2.xy, n1.z));
Using the concept of dividing the rgb vector by its length as my "normalizing" method.
For any vector V = (x, y, z), |V| = sqrt(xx + yy + z*z) gives the
length of the vector. When we normalize a vector, we actually
calculate V/|V| = (x/|V|, y/|V|, z/|V|).
img1 = cv2.imread(str(base_image)).astype(np.float32)
img2 = cv2.imread(str(top_image)).astype(np.float32)
# img = img1 + img2 # Could just do this to combine r,g channels?
(b1, g1, r1) = cv2.split(img1)
(b2, g2, r2) = cv2.split(img2)
r = r1 + r2
g = g1 + g2
b = b1
r_norm = []
g_norm = []
for (_r, _g, _b) in zip(r.ravel(), g.ravel(), b.ravel()):
_l = length(_r, _g, _b)
r_norm.append((_r / _l)*255)
g_norm.append((_g / _l)*255)
r = np.reshape(r_norm, (-1, 2048))
g = np.reshape(g_norm, (-1, 2048))
img = np.dstack((b, g, r))
cv2.imwrite(str(output_path), img)
where length is defined as:
def length(r, g, b):
return math.sqrt((r ** 2 + g ** 2 + b ** 2))
But its not working..I get a very gray image.
On the side this process is slow so if anyone has ideas to speed up the loop (or remove it entirely) that would be awesome :). Been pulling my hair out on this one...

Color Transfer Between Two Image with One Image as Plain Color

I came across this particular color-transfer tutorial using OpenCV:
https://www.pyimagesearch.com/2014/06/30/super-fast-color-transfer-images/
and implemented it like this:
def color_transfer(source, target):
# compute color statistics for the source and target images
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
# compute color stats for both images
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = self.image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = self.image_stats(target)
# split the color space
(l, a, b) = cv2.split(target)
# substract the means from target image
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# check values
print(lStdSrc, aStdSrc, bStdSrc)
print(lStdTar, aStdTar, bStdTar)
print(lMeanSrc, aStdSrc, bMeanSrc)
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
# add the source mean
l += lMeanSrc
a += aMeanSrc
b += bMeanSrc
# clipping the pixels between 0 and 255
l = np.clip(l, 0, 255)
a = np.clip(a, 0, 255)
b = np.clip(b, 0, 255)
# merge the channels
transfer = cv2.merge([l, a, b])
# converting back to BGR
transfer = cv2.cvtColor(transfer.astype("uint8"), cv2.COLOR_LAB2BGR)
return transfer
In this particular code:
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
it gets the standard deviation of the source, so when we combine the source and the target image, it will become a plain image as well since the lab will all be 0.
How can I fix this? It works when the source image is not a plain image with color.

How can I detect a 'dark' image border and crop to it using Python (or Perl)?

I have a number of small images that are screen captures from a video. A couple of example images follow (with various typesof edges present):
In short, I'm trying to crop the image to the closest part of the 'main' image, which is inside an (almost) uniformly 'black' border... or sometimes, there's a bit of a 'jittery' edge. You could think of it as going to the centre of the image and then radiate out until you hit a 'rectangular ('black' or 'nearly black') border'.
The biggest issue as near as I can see is to determine the location and dimensions of the 'cropping rectangle' around the image.. but so far, I haven't been able to get anywhere with doing that.
I've tried using 'cropdetect' filters in ffmpeg; there's not anything really helpful with Perl; ...and as I'm new to Python, I still haven't worked-out if there's any simple module that can do what I need. I have looked at 'scikit-image'... but was totally bamboozled by it, as I don't have a good enough knowledge of Python, let alone a sufficientlly 'technical' knowledge of image formats, colour depth, manipulation techniques, etc that would let me use 'scikit-image'.
I'd appreciate any suggestions on how to tackle this problem, even better if there was a simple way to do it. From my little bit of understanding of 'scikit-image', it seems like the 'Canny edge detect' or the 'prewitt_v'/'prewitt_h' filters might be relevant...?
I'm using Python 3.7.0 (and Active State Perl v5.20.2, if there's any way to use that), both running under Windows 8.1.
Thanks a lot for any forthcoming suggestions.
I've made an attempt at solving this... but it's not very 'robust'. It uses the luminance values of the pixels when the image has been greyscaled:-
# ----
# this will find the 'black'-ish portions and crop the image to these points
# ozboomer, 25-Apr-2020 3-May-2020
#
# ---------
import pprint
import colorsys
from PIL import Image, ImageFilter
# ---- Define local functions (I *still* don't understand why I have to put these here)
def calculate_luminances(r, g, b):
"""Return luminance values of supplied RGB and greyscale of RGB"""
lum = (0.2126 * r) + (0.7152 * g) + (0.0722 * b) # luminance
H, S, V = colorsys.rgb_to_hsv(r, g, b) # HSV for the pixel RGB
R, G, B = colorsys.hsv_to_rgb(H, 0, V) # ...and greyscale RGB
glum = (0.2126 * R) + (0.7152 * G) + (0.0722 * B) # greyscale luminance
return(lum, glum)
# end calculate_luminances
def radial_edge(radial_vector, ok_range):
"""Return the point in the radial where the luminance marks an 'edge' """
print("radial_edge: test range=", ok_range)
edge_idx = -1
i = 0
for glum_value in radial_vector:
print(" radial_vector: i=", i, "glum_value=", "%.2f" % round(glum_value, 2))
if int(glum_value) in ok_range:
print(" IN RANGE! Return i=", i)
edge_idx = i
break
i = i + 1
# endfor
return(edge_idx)
# ---- End local function definitions
# ---- Define some constants, variables, etc
#image_file = "cap.bmp"
#image_file = "cap2.png"
#image_file = "cap3.png"
image_file = "Sample.jpg"
#image_file = "cap4.jpg"
output_file = "Cropped.png";
edge_threshold = range(0, 70) # luminance in this range = 'an edge'
#
# The image layout:-
#
# [0,0]----------+----------[W,0]
# | ^ |
# | | |
# | R3 |
# | | |
# +<--- R1 ---[C]--- R2 --->+
# | | |
# | R4 |
# | | |
# | v |
# [0,H]----------+----------[W,H]
#
# -------------------------------------
# Main Routine
#
# ---- Get the image file ready for processing
try:
im = Image.open(image_file) # RGB.. mode
except:
print("Unable to load image,", image_file)
exit(1)
# Dammit, Perl, etc code is SO much less verbose:-
# open($fh, "<", $filename) || die("\nERROR: Can't open file, '$filename'\n$!\n");
print("Image - Format, size, mode: ", im.format, im.size, im.mode)
W, H = im.size # The (width x height) of the image
XC = int(W / 2.0) # Approx. centre of image
YC = int(H / 2.0)
print("Image Centre: (XC,YC)=", XC, ",", YC)
# --- Define the ordinate ranges for each radial
R1_range = range(XC, -1, -1) # Actual range: XC->0 by -1 ... along YC ordinate
R2_range = range(XC, W, 1) # : XC->W by +1 ... along YC ordinate
R3_range = range(YC, -1, -1) # : YC->0 by -1 ... along XC ordinate
R4_range = range(YC, H, 1) # : YC->H by +1 ... along XC ordinate
# ---- Check each radial for its 'edge' point
radial_luminance = []
for radial_num in range (1,5): # We'll do the 4 midlines
radial_luminance.clear()
if radial_num == 1:
print("Radial: R1")
for x in R1_range:
R, G, B = im.getpixel((x, YC))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", x, ",", YC, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
left_margin = XC - radial_edge(radial_luminance, edge_threshold)
elif radial_num == 2:
print("Radial: R2")
for x in R2_range:
R, G, B = im.getpixel((x, YC))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", x, ",", YC, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
right_margin = XC + radial_edge(radial_luminance, edge_threshold)
elif radial_num == 3:
print("Radial: R3")
for y in R3_range:
R, G, B = im.getpixel((XC, y))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", XC, ",", y, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
top_margin = YC - radial_edge(radial_luminance, edge_threshold)
elif radial_num == 4:
print("Radial: R4")
for y in R4_range:
R, G, B = im.getpixel((XC, y))
[lum, glum] = calculate_luminances(R, G, B)
print(" CoOrd=(", XC, ",", y, ") RGB=",
(R, G, B), "lum=", "%.2f" % round(lum, 2),
"glum=", "%.2f" % round(glum, 2))
radial_luminance.append(glum)
# end: get another radial pixel
bottom_margin = YC + radial_edge(radial_luminance, edge_threshold)
# end: which radial we're processing
im.close()
crop_items = (left_margin, top_margin, right_margin, bottom_margin)
print("crop_items:", crop_items)
# ---- Crop the original image and save it
im = Image.open(image_file)
im2 = im.crop(crop_items)
im2.save(output_file, 'png')
exit(0)
# [eof]
I would expect the radial_edge() function would need to be modified to do something about checking the surrounding pixels to determine if we have a real edge... 'coz the current ok_range probably needs to be determined for each image, so there's no point to trying to automate the cropping using a script such as this.
Still looking for a robust and reliable way to attack this problem...

Anamorphosis in Python

I tried to do anamorphosis on an image by following this link
https://github.com/aydal/Cylinderical-Anamorphosis/blob/master/anamorph.py
It gives an anamorphic image but it gives that image in the half circle. But I want the output in a full circle size.
I tried with
warp[c-j, i-1] = img[p-1, q-1]
warp[c+j, i-1] = img[p-1, q-1]
Instead of warp[c-j, i-1] = img[p-1, q-1]
But it doesn't give one image in the full circle rather creates same output twice!
Can anyone please help me.
Complete Code:
import math
from cv2 import *
import numpy as np
img = imread("test.jpg")
(rows, cols) = (img.shape[0], img.shape[1])
r = 0 #offset-gives space to keep cylinder and height of the image from bottom: original: math.trunc(.25*rows)
c = rows #this will be the decisive factor in size of output image-maximum radius of warped image: original: c = r+rows
warp = np.zeros([c,2*c,3], dtype=np.uint8)
def convert(R, b):
return math.trunc(b*rows/(2*math.asin(1))), math.trunc(c-R)
for i in range(0, 2*c):
for j in range(1, c):
b = math.atan2(j, i-c)
R = math.sqrt(j*j+math.pow(i-c, 2))
if R>=r and R<=c:
(q, p) = convert(R, b)
warp[c-j, i-1] = img[p-1, q-1]
#warp[c+j, i-1] = img[p-1, q-1]
imshow("Output", warp)
waitKey()
The original image
My output image (half circle)
Desired output image
Similar to the column offset you should include an offset for the rows as well when computing b and R. Since the warped image has c rows the offset is c//2:
b = math.atan2(j - c//2, i-c)
R = math.sqrt((j - c//2)**2 + math.pow(i-c, 2))
Note that the warped image is not a perfect circle as you specified it be double as wide as high. If you want a full circle you should also adjust the upper boundary check for R to be c//2 as this is the max. radius along the rows:
if r <= R <= c//2:
...
And similarly you need to adjust the computation in convert:
return ..., math.trunc(c//2 - R)
But then, in any case, you could just use a square image right from the beginning, i.e. specify warp.shape == (c, c).
Edit
Updated code, uses original dimensions for warped image:
import math
import cv2
import numpy as np
img = cv2.imread("/tmp/img.jpg")
(rows, cols) = (img.shape[0], img.shape[1])
r = 0
c = rows // 2
warp = np.zeros([rows, cols, 3], dtype=np.uint8)
def convert(R, b):
return math.trunc(c * (1 - b/math.pi)), 2*math.trunc(c - R) - 1
for i in range(0, cols):
for j in range(0, rows):
b = math.atan2(j - c, i - c)
R = math.sqrt((j - c)**2 + (i - c)**2)
if r <= R <= c:
q, p = convert(R, b)
warp[j, i] = img[p, q]
cv2.imshow("Output", warp)
cv2.waitKey()
And output image:

Categories