Converting RGB to Hex - python

I'm looking for a way to modify my code to convert the RGB pixel data into hexadecimal pixel data. Such as converting 37, 4, 201 to #2504C9. Code attached, if anyone knows how to do this, I'd really appreciate it! I've tried several methods from here but so far haven't been able to find much of anything that works.
from PIL import Image
import sys
im = Image.open(r"C:\Users\AChri\Desktop\boio.png")
px = im.load()
w, h = im.size
x = 0
y= 0
while True:
if x >= w:
x = 0
y= y+1
else:
if y >= h:
print('Done!')
sys.exit()
else:
val = px[x, y]
print(px[x, y])
x = x+1

In px[x,y] you have a tuple (R, G, B), to print it as hex you can just do the following:
print("#{:02X}{:02X}{:02X}".format(*px[x,y]))
Or, to adapt it to your code:
val = "#{:02X}{:02X}{:02X}".format(*px[x,y])
print(val)

Related

PIL giving error when trying to run Floodfill, need to change to Turtle

Im trying to make a BFS Floodfill with PIL, but i can't find how to fix the import erros, and I need to translate it to Python Turtle
from queue import Queue
import queue
from PIL import Image
imagen = Image.open("Imagen.png")
ROJO = (255, 0, 0)
x, y = 0, 0
floodfill(imagen, x, y, ROJO)
imagen.save("ImagenResultado.png")
def floodfill(grid, i, j, nuevo_color):
w = imagen.width
h = imagen.height
viejo_color = imagen.getpixel((x, y))
queue = Queue()
queue.put((x, y))
while not queue.empty():
x, y = queue.get()
if x < 0 or x >= w or y < 0 or y >= h or imagen.getpixel((x, y)) != viejo_color:
continue
else:
imagen.putpixel((x, y), nuevo_color)
queue.put((x+1,y))
queue.put((x-1,y))
queue.put((x,y+1))
queue.put((x,y-1))
you are calling floodfill(...) before defining it.
and as a bonus tip, you are using x and y instead of i and j within the function definition.
I'm assuming that the bad formatting is just an oversight, but if not, the lack of correct whitespace will cause python errors too. None of this is due to PIL.

matlab colormap in python

I need the orignal image once again but its returning greyscale
my teacher said do colormap at the beginning and said that it happens in matlab. so i want to do similar task in python too
Here is my code have a look
please help
ENCRYPTION:
import numpy as np
from PIL import Image
x = Image.open('1.jpg', 'r')
x = x.convert('L')
y = np.asarray(x.getdata(), dtype=np.int).reshape((x.size[1], x.size[0]))#changed image to matrix getdata for matrix value # dtype is int type reshape used to break 1d array into 2d array
y = np.asarray(y, dtype=np.uint8)#if values still in range 0-255!
#print(y)
z = y
w = Image.fromarray(y, mode='L')
w.save('grey_scale.bmp')
for i in range(len(z)):
for j in range(len(z[i])):
a = z[i][j]
p = int(bin(a)[2:])
p = '%08d' % p
p = p[::-1]
z[i][j] = int(p, 2)
#print(z)
C = Image.fromarray(z)
C.save('decryption.bmp')
print("DONE")
DECRYPTION:
import numpy as np
from PIL import Image
x = Image.open('decryption.bmp', 'r')
y = np.asarray(x.getdata(), dtype=np.int).reshape((x.size[1], x.size[0]))#changed image to matrix getdata for matrix value
#print(y) # dtype is int type reshape used to break 1d array into 2d array
y = np.asarray(y, dtype=np.uint8)#if values still in range 0-255!
#print(y)
z = y
for i in range(len(z)):
for j in range(len(z[i])):
a = z[i][j]
p = int(bin(a)[2:])
p = '%08d' % p
p = p[::-1]
z[i][j] = int(p, 2)
#print(z)
C = Image.fromarray(z)
C.save('Final.bmp')
print("DONE")
I think(?) what you're looking for is a Colour Mapping function like:
def create_colourmap(colour, grey):
c_map = numpy.zeros((256,4), dtype=numpy.float64)
for i in range(colour.shape[0]):
for j in range(colour.shape[1]):
tone = grey[i,j]
c_map[tone,3] +=1
count = c_map[tone, 3]
c_map[tone,:3] = (c_map[tone,:3] * (count-1) + colour[i,j])/count
return c_map.astype(numpy.uint8)[:,:3]
Which would give you ONE colour value for each Greyscale value (or Tone).
Your 'bit reversal' procedure could be simplified by another function:
def reverse_bits(arr):
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
arr[i][j] = int('{0:08b}'.format(arr[i][j])[::-1], 2)
return arr
Putting this all together, your encrypt function would be:
def encrypt(infile, outfile):
with Image.open(infile, 'r') as colour_img:
colour_arr = numpy.array(colour_img)
grey_img = colour_img.convert('L')
grey_arr = numpy.array(grey_img)
c_map = create_colourmap(colour_arr, grey_arr)
with Image.fromarray(c_map) as cmap_img:
cmap_img.save(outfile[:-4]+'_cmap.bmp')
grey_arr = reverse_bits(grey_arr)
with Image.fromarray(grey_arr) as c:
c.save(outfile)
print("Encryption DONE")
And your decrypt function:
def decrypt(infile, outfile):
with Image.open(infile, 'r') as x:
y = numpy.array(x)
y = reverse_bits(y)
colour_arr = numpy.zeros((y.shape[0], y.shape[1], 3), dtype=numpy.uint8)
with Image.open(infile[:-4]+'_cmap.bmp') as cmap_img:
cmap = numpy.array(cmap_img)
for i in range(256):
colour_arr[y==i] = cmap[i]
with Image.fromarray(colour_arr) as c:
c.save(outfile)
print("Decryption DONE")
You'll notice that the Colour Mapping will not completely restore the image colour, but will give the image some hue. I don't know what your assignment is about, but you may want to send the Colour Map along with the encrypted image, or give them another image with similar colouring.
I hope this helps you, but you will need to lean how this works, and comment where necessary to explain whats going on.
Good luck!

Writing a mandelbrot set to an image in python

I am trying to write a mandelbrot set to an image in python, and am having a problem with one of my functions.
The issue is: While I expect something like this. I am getting a plain white image. Here is my code:
Quick Summary of code:
Check if value is in set, if it is, mark it as true in an array of booleans. Then, draw the image based on the array of booleans, coloring the true, and leaving the false ones.
import math
import numpy as np
import scipy.misc as smp
from PIL import PILLOW_VERSION
from PIL import Image
def iterate(x, y, iterationNum):
z = 0
coord = complex(x, y)
for a in xrange(iterationNum):
#Don't use fabs. It can be negative.
z = z * z + coord
#This is a comparison between complex and int. It probably won't work.
#You want |Z| which is: z.real ** 2 + z.imag ** 2 > 4
if math.fabs(z) > 2:
return False
return True
def pixel(image,x,y,r,g,b):
"""Place pixel at pos=(x,y) on image, with color=(r,g,b)"""
image.put("#%02x%02x%02x" % (r,g,b), (y, x))
#here's some example coloring code that may help:
def draw(grid):
#Create a white image with the size of the grid as the number of pixels
img = Image.new('RGB', (len(grid), len(grid)), "white")
pixels = img.load()
for row in xrange(len(grid)):
for col in xrange(len(grid[row])):
if grid[row][col] == True:
#If that point is True (it's in the set), color it blue
pixels[row, col] = (0, 0, 255)
return img
def mandelbrot():
#you should probably use a square, it's easier to deal with
#The mandelbrot set fits completely within (-2, 2) and (2, -2)
#(-200, 200), (200, -200) is way too big!
TopLeftX = -2; BottomRightX = 2
TopLeftY = 2; BottomRightY = -2
#increment should be calculated based on the size of the bounds and the number of pixels
#For example, if you're between -2 and 2 on the X-Plane, and your image is 400 pixels wide
#Then your increment = (2 - (-2)) / 400 = 4 / 400 = .01 so that each pixel is 1/400th of the
#Total width of the bounding area
increment = 0.01
maxIt = 100
w = BottomRightX - TopLeftX
h = TopLeftY - BottomRightY
#This should be based on the size of the image, one spot in the area for one pixel
npArr = np.zeros((w / increment, h / increment), dtype=bool)
#Use the increment variable from above. It won't work with xrange because that doesn't
#Support decimals. You probably want to use a while loop or something
x = -2
y = 2
while TopLeftX <= x <= BottomRightX:
while TopLeftY <= y <= BottomRightY:
#I recommend using True or False in here (in the set or not)
#And then do your color calculations as I explained above
#Saves a lot of memory
if iterate(x, y, maxIt):
npArr[x, y] = True
y += increment
#once you've calculated the Trues and Falses, you'd call the draw() function
#using the npArr as the parameter. I haven't tested the code, so there may
#be a few bugs, but it should be helpful!
x += increment
return npArr
img = draw(mandelbrot())
img.save("mandelbrot.png")
I suspect the problem is with the "iterate" function in my code, because none of the values i put in iterate are returning true.
EDIT
I have another issue as well, The second for loop I have here isnt even running.
Your handling of the y coordinate is faulty. You begin the outer loop with
y = 2
and have the loop condition as
while TopLeftY <= y <= BottomRightY:
After substituting their values, this is
while 2 <= y <= -2:
which is a nonsense. This is followed by
y += increment
but y is already at the top end of the range. Moreover, you fail to reset y for each inner loop.
To summarise, the loop should be
x = TopLeftX # use the value you already defined!
while TopLeftX <= x <= BottomRightX:
y = TopLeftY # moved to inside x loop
while TopLeftY >= y >= BottomRightY: # change the loop condition
# ... the Mandelbrot iteration
y -= increment # reverse direction
x += increment
I am no Python expert, so there may be other problems too.

How to find the colour of main object in an fixed sized image

My aim is to find the color of main object in a frame/image. In my case image is always of same type. For example News reporter(human) in Forest or News reporter in Animal farm.The position of news reporter is also same.What is the simple solution to find out the dominant colour of the main object(News Reporter)
Any help is welcome.Thanks
EDIT Code added
import cv2
from collections import namedtuple
from math import sqrt
import random
import webcolors
try:
import Image
except ImportError:
from PIL import Image
Point = namedtuple('Point', ('coords', 'n', 'ct'))
Cluster = namedtuple('Cluster', ('points', 'center', 'n'))
def get_points(img):
points = []
w, h = img.size
for count, color in img.getcolors(w * h):
points.append(Point(color, 3, count))
return points
rtoh = lambda rgb: '#%s' % ''.join(('%02x' % p for p in rgb))
def colorz(filename, n=3):
img = Image.open(filename)
img.thumbnail((200, 200))
w, h = img.size
points = get_points(img)
clusters = kmeans(points, n, 1)
rgbs = [map(int, c.center.coords) for c in clusters]
return map(rtoh, rgbs)
def euclidean(p1, p2):
return sqrt(sum([
(p1.coords[i] - p2.coords[i]) ** 2 for i in range(p1.n)
]))
def calculate_center(points, n):
vals = [0.0 for i in range(n)]
plen = 0
for p in points:
plen += p.ct
for i in range(n):
vals[i] += (p.coords[i] * p.ct)
return Point([(v / plen) for v in vals], n, 1)
def kmeans(points, k, min_diff):
clusters = [Cluster([p], p, p.n) for p in random.sample(points, k)]
while 1:
plists = [[] for i in range(k)]
for p in points:
smallest_distance = float('Inf')
for i in range(k):
distance = euclidean(p, clusters[i].center)
if distance < smallest_distance:
smallest_distance = distance
idx = i
plists[idx].append(p)
diff = 0
for i in range(k):
old = clusters[i]
center = calculate_center(plists[i], old.n)
new = Cluster(plists[i], center, old.n)
clusters[i] = new
diff = max(diff, euclidean(old.center, new.center))
if diff < min_diff:
break
return clusters
def main():
img = cv2.imread('d:/Emmanu/project-data/b1.jpg')
res=cv2.resize(img,(400,300))
crop_img = res[100:200, 150:250]
cv2.imwrite("d:/Emmanu/project-data/color-test.jpg", crop_img)
g= colorz('d:/Emmanu/project-data/color-test.jpg',1)
k=g[0]
print k
f=webcolors.hex_to_rgb(k)
print webcolors.rgb_to_name(f, spec='css3')
if __name__ == '__main__':main()
The problem is this returns the major color in the whole image not the main object
If your taking the colour of whole image,in most cases you will get wrong answer since background is more.If your image size is fixed and you are sure about object's position The most simple solution is Crop the image at where you expect the object.In most cases it will work.
In order to crop
import cv2
img = cv2.imread("'d:/Emmanu/project-data/b1.jpg'")
crop_img = img[200:400, 100:300] # Crop from x, y, w, h -> 100, 200, 300, 400
# NOTE: its img[y: y + h, x: x + w] and *not* img[x: x + w, y: y + h]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)
Now give this crop_image as input to your code.And in most cases it will give correct solution.There is nothing more simple that this.I think this will help.

Is there a nice way to slice Python numpy ndarrays without checking sign of the bounds?

This is part of some code I've been working on to quickly align images. It works well, but the syntax is ugly. Is there a better way to write this?
def shift_int(image, base, y, x):
"""
Quickly shift an image with respect to a base and return a parameter that
is minimized when the images are well aligned, and not biased towards
large shifts
image -- The input image that is shifted
base -- The second image to match
y -- An offset along axis 0
x -- An offset along axis 1
"""
new_image = image.copy()
new_base = base.copy()
if y > 0:
new_image = new_image[:-y]
new_base = new_base[y:]
if y < 0:
new_image = new_image[-y:]
new_base = new_base[:y]
if x > 0:
new_image = new_image[:,:-x]
new_base = new_base[:,x:]
if x < 0:
new_image = new_image[:,-x:]
new_base = new_base[:,:x]
return np.mean((new_im-new_base)**2)
h, w = np.shape(new_image)
new_image = new_image[max(0, -y):min(h, h-y),max(0, -x):min(w, w-x)]
h, w = np.shape(new_base)
new_base = new_base[max(0, y):min(h, h+y),max(0, x):min(w, w+x)]

Categories