python image scrambeling porgram - python

I'm writing an image scrambling and Unscrambling program. I'm transfering a custom seed to the random function in order scramble the image pixels in a way that I could unscramble them with the same seed. The scramble part works fine but when I unscramble the scrambled image it leaves some pixels black, I tired using png format since its not being compressed but still no good.
Here is my code:
from PIL import Image
import random
from datetime import datetime
class Scrambler:
#staticmethod
def scramble(key,fileName):
image = Image.open(fileName)
pixels = image.load()
new_image = Image.new(image.mode,image.size)
new_image_pix = new_image.load()
seed = 0
for c in key:
seed+=ord(c)
random.seed(seed)
for i in range(0,(image.size)[0]):
for j in range(0,(image.size)[1]):
new_image_pix[i,j] = pixels[random.randint(0,image.size[0]-1),
random.randint(0,image.size[1]-1)]
new_image.show()
new_image.save('scrambeld.png')
#staticmethod
def unscramble(key,fileName):
image = Image.open(fileName)
pixels = image.load()
new_image = Image.new(image.mode,image.size)
new_image_pix = new_image.load()
seed = 0
for c in key:
seed+=ord(c)
random.seed(seed)
for i in range(0,(image.size)[0]):
for j in range(0,(image.size)[1]):
new_image_pix[random.randint(0,image.size[0]-1),
random.randint(0,image.size[1]-1)] = pixels[i,j]
new_image.show()
new_image.save('unscarmbeld.png')
original image:
scrambeld image:
image after Un Scrambeling:
Much appreciate any help.

You don't insure that every pixel in the original images gets placed (assigned from) in the scrambled image, which means that those pixels won't get filled in in the unscrambled image.

Related

saving image using matplotlib in python

I'm trying to make a simple code that loads an image, divide the value of each pixel by 2 and stores the image. The image is stored in an array [1280][720][3]. After changing the value of each pixel I've chequed that the values are the expected. For some reason the values are correct but when I store the new image and check it, the values of the pixels are not the same as before...
The image is 1280x720 pixels and each pixel has 3 bytes (one for each color rgb)
import matplotlib.image as mpimg
img = mpimg.imread('image.jpg') # (1280, 720, 3)
myImg = []
for row in img:
myRow = []
for pixel in row:
myPixel = []
for color in pixel:
myPixel.append(color // 2)
myRow.append(myPixel)
myImg.append(myRow)
mpimg.imsave("foo.jpg", myImg)
img is a numpy array, so you can just use img / 2. It's also much faster than using a list loop.
myImg = img / 2
mpimg.imsave("foo.jpg", myImg)

Putpixel function not generating all the pixels

My goal is to generate a color per pixel in order to fill up the whole canvas however the image generated always turns out black with only one of its pixels changed color, I can't seem to figure what I'm doing wrong.
import random
from PIL import Image
canvas = Image.new("RGB", (300,300))
y = random.randint(1, canvas.width)
x = random.randint(1, canvas.width)
r = random.randint(0,255)
g = random.randint(0,255)
b = random.randint(0,255)
rgb = (r,g,b)
for i in range(canvas.width):
canvas.putpixel((x,y), (rgb))
canvas.save("test.png", "PNG")
print("Image saved successfully.")
You really should try and avoid using for loops in any Python image processing - they are slow and error-prone.
The easiest and fastest way to make a random image is using vectorised Numpy functions like this:
import numpy as np
from PIL import Image
# Create Numpy array 300x300x3 of random uint8
data = np.random.randint(0, 256, (300,300,3), dtype=np.uint8)
# Make into PIL Image
im = Image.fromarray(data)
The problem with your code is that you are not iterating over every pixel. I've modified your code to iterate over every pixel, check whether or not it is black (0,0,0), then place a pixel on that iteration with your randomly-generated rgb value. Then, I regenerate 3 new random numbers and place them back into the rgb tuple causing the next pixel in the loop to have a different rgb value.
The x and y definitions are redundant, as you want a random color for every pixel but do not want random pixels, so I have removed them. I added a declaration, pixels = canvas.load() which allocates memory for the pixels so you can iterate over them and change each individual color. I heavily relied on this similar stackoverflow question, if you want further information. Here is my code:
canvas = Image.new("RGB", (300,300))
pixels = canvas.load()
width, height = canvas.size
for i in range(width):
for j in range(height):
if pixels[i,j] == (0,0,0):
r = random.randint(0,255)
g = random.randint(0,255)
b = random.randint(0,255)
rgb = (r,g,b)
canvas.putpixel((i,j), (rgb))
canvas.save("test.png", "PNG")
print("Image saved successfully.")
Here is the output produced:

Making image brightened in python using putdata

This is the question:
Write a program in Python which opens the file 'pixerror.png', removes the S&P noise and will correct the brightness of the image, save the processed photo under another name. You have to look pixel for pixel and cannot use blurb functions.
My fist task is to get the image brighter.
I used this question code, but i cannot solve my error that I have. This error:
_
ruisclasse.py 41
putdata exceptions.SystemError:
new style getargs format but argument is not a tuple
_
And this is my code.
_
from __future__ import division #for floating number
from PIL import Image
import cv2
filename='pixerror.png'
action = 'lighten'
extent = 10
#load the original image into a list
original_image = Image.open(filename, 'r')
pixels = original_image.getdata()
#initialise the new image
new_image = Image.new('RGB', original_image.size)
new_image_list = []
brightness_multiplier = 1.1
if action == 'lighten':
brightness_multiplier += (extent/100)
else:
brightness_multiplier -= (extent/100)
#for each pixel, append the brightened or darkened version to the new image list
for pixel in pixels:
new_pixel = (int(pixel[0] * brightness_multiplier),
int(pixel[1] * brightness_multiplier),
int(pixel[2] * brightness_multiplier))
#check the new pixel values are within rgb range
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(new_pixel)
#save the new image
new_image.putdata(new_image_list)
new_image.save('colour_brightness.jpg')
cv2.waitKey(0)
cv2.destroyAllWindows()
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(new_pixel)
You're appending lists to new_image_list, but you should be appending tuples.
new_pixel= [max(min(channel, 255), 0) for channel in new_pixel]
new_image_list.append(tuple(new_pixel))

Python Image.load() returning pixels greater than 250

I am loading my Image file using Image.open("image.tif"). Then i am using Image.load() to generate a pixelMap of the image. Then i am storing each pixel into an array. The following code describes this process. Then I want to create the ascii value of each pixel and store it in a string. So I going through each pixel in my pixel array and then change the pixel value to ascii value. However I am having an error because I am getting some pixel values greater than 250. How is this possible. Also, it is b/w image. What am I doing wrong?
self.filename = filename
self.im = Image.open(filename)
self.pixelmap = self.im.load() #Loads the image as a map of pixels
self.arr = []
for i in range(self.im.size[0]):
for j in range(self.im.size[1]):
mypixel = self.pixelmap[i, j]
self.arr.append(mypixel)
for i in msgFile.arr:
self.message += str(unichr(int(i)))
something like this?
from PIL import Image
import numpy as np
image = np.asarray(Image.open('image.jpg'))
_y, _x, _z = image.shape
str_array = [str(image[y][x]) for y in range(_y) for x in range(_x)]

Auto-cropping images with PIL

I have folder full of images with each image containing at least 4 smaller images. I would to know how I can cut the smaller images out using Python PIL so that they will all exist as independent image files. fortunately there is one constant, the background is either white or black so what I'm guessing I need is a way to the cut these images out by searching for rows or preferably columns which are entirely black or entirely white, Here is an example image:
From the image above, there would be 10 separate images, each containing a number. Thanks in advance.
EDIT: I have another sample image that is more realistic in the sense that the backgrounds of some of the smaller images are the same colour as the background of the image they are contained in. e.g.
The output of which being 13 separate images, each containng 1 letter
Using scipy.ndimage for labeling:
import numpy as np
import scipy.ndimage as ndi
import Image
THRESHOLD = 100
MIN_SHAPE = np.asarray((5, 5))
filename = "eQ9ts.jpg"
im = np.asarray(Image.open(filename))
gray = im.sum(axis=-1)
bw = gray > THRESHOLD
label, n = ndi.label(bw)
indices = [np.where(label == ind) for ind in xrange(1, n)]
slices = [[slice(ind[i].min(), ind[i].max()) for i in (0, 1)] + [slice(None)]
for ind in indices]
images = [im[s] for s in slices]
# filter out small images
images = [im for im in images if not np.any(np.asarray(im.shape[:-1]) < MIN_SHAPE)]

Categories

Resources