Increasing image width by one pixel - python

I am trying to implement a program, that will increase the width of an image by one pixel. I then want to take the new maximum x ordinate and put this with a random y ordinate (that is within the range of the image) to create a new pixel.
for x in range (0,getWidth(pic)):
for y in range (0,getHeight(pic)):
X=getWidth(pic)
newX = (X+1)
colr=(255,0,0)
newPixel = getPixel (pic, newX, y)//line 25
setColor(newPixel, colr)
Y=getHeight(pic)
newY= (Y+1)
newPixel = getPixel( pic,x, newY)
setColor(newPixel, colr)
I get this error:
getPixel(picture,x,y): x (= 226) is less than 0 or bigger than the width (= 224)
The error was:
Inappropriate argument value (of correct type).
An error occurred attempting to pass an argument to a function.
Please check line 25 of D:\bla bla
I understand it is out of the range. What am I doing wrong?

Here is generalized approach to increase the size of an image keeping its current content:
Feel free to adapt.
# Increase a picture given an offset, a color and the anciant
# content must be centered or not.
# Offsets must be positive.
def increaseAndCopy(pic, offsetX, offsetY, bg_color=black, center=True):
# Offsets must be positive
if (offsetX < 0.0) or (offsetY < 0.0):
printNow("Error: Offsets must be positive !")
return None
new_w = pic.getWidth() + int(2*offsetX)
new_h = pic.getHeight() + int(2*offsetY)
startX = 0
startY = 0
if (center) and (offsetX > 1.0):
startX = int(offsetX)
if (center) and (offsetY > 1.0):
startY = int(offsetY)
new_pic = makeEmptyPicture(new_w, new_h)
# Fill with background color
setAllPixelsToAColor(new_pic, bg_color)
# Process copy
for x in xrange(pic.getWidth()):
for y in xrange(pic.getHeight()):
px = getPixel(pic, x, y)
new_px = getPixel(new_pic, x + startX, y + startY)
setColor(new_px, getColor(px))
return new_pic
file = pickAFile()
picture = makePicture(file)
# Pass an offset of 0.5 to increase by 1 pixel
#new_picture = increaseAndCopy(picture, 0.5, 0, blue)
new_picture = increaseAndCopy(picture, 10, 20, gray, True)
if (new_picture):
writePictureTo(new_picture, "/home/biggerPic.png")
show(new_picture)
Output (Painting by Jean-Michel Basquiat):
...........................................................

How can you get something that an object does not have?
newPixel = getPixel (pic, newX, y)//line 25
The original image remains sized at getWidth(pic) but you are asking for a pixel at getWidth(pic) + 1 which does not exist.
You can enlarge the image by copying it to a new picture similar to this answer.
...
newPic=makeEmptyPicture(newX,newY)
xstart=0
ystart=0
for y in range(ystart,newY):
for x in range(xstart, newX):
if x == newX or y == newY:
colour=(255,0,0)
else:
oldPixel=getPixel(oldPic,x,y)
colour=getColor(oldPixel)
newPixel=getPixel(newPic,x,y)
setColor(newPixel,colour)
explore(newPic)

Related

How to filter specific image coordinates from an image

I am reading an image, getting objects that have a certain brightness value, and then plotting the X and Y coords to the image.
But, there is a huge group of outliers, which are all located in a rectangular part of the image, Its X and Y coords are 1110-1977 (width) and 1069-1905 (height). From here, I'm looping through this little square portion of the image, and from my pre-created x and y arrays any values that have the same coords as shown there are removed.
However, this removes a lot more coords, which, for example, have X in the range 1110-1977. So the end result is a cross pattern filtering when I only want the square in the center to be filtered. How would I do this?
Code
from PIL import Image, ImageDraw
import numpy as np
from math import sqrt
imag = Image.open("Centaurus_A-DeNoiseAI-denoise.jpg")
imag = imag.convert ('RGB')
x=[]
y=[]
imag2=Image.open("Cen_A_cropped.jpg")
imag2=imag2.convert('RGB')
r=[]
g=[]
b=[]
width2, height2=imag2.size
for count2 in range(width2):
for i2 in range(height2):
X,Y=count2,i2
(R,G,B)=imag2.getpixel((X,Y))
r.append(R)
g.append(G)
b.append(B)
average_r=sum(r)/len(r)
average_g=sum(g)/len(g)
average_b=sum(b)/len(b)
brightness_average=sqrt(0.299*(average_r**2) + 0.587*(average_g**2) + 0.114*(average_b**2))
print("Avg. brightness "+str(brightness_average))
def calculate_brightness(galaxy,ref_clus,clus_mag):
delta_b=(galaxy/ref_clus)
bright=delta_b**2
mag=np.log(bright)/np.log(2.512)
return mag+clus_mag
count=0
X,Y = 1556,1568
(R,G,B) = imag.getpixel((X,Y))
width, height=imag.size
brightness = sqrt(0.299*(R**2) + 0.587*(G**2) + 0.114*(B**2))
print("Magnitude: "+str((calculate_brightness(13050, 15.79,3.7))))
reference=brightness_average/(calculate_brightness(13050, 15.79,3.7)/6.84)
print("Reference: "+str(reference))
for count in range(width):
for i in range(height):
X,Y = count,i
(R,G,B) = imag.getpixel((X,Y))
brightness = sqrt(0.299*(R**2) + 0.587*(G**2) + 0.114*(B**2))
if(reference<=brightness<=reference+3):
x.append(X)
y.append(Y)
#post processing----------------------------------------------------------------------------------------------------
for x2 in range(1110, 1977):
for y2 in range(1069, 1905):
X,Y=x2,y2
if(X in x and Y in y):
x.remove(X)
y.remove(Y)
#-------------------------------------------------------------------------------------------------------------------
with imag as im:
delta = 19
draw = ImageDraw.Draw(im)
for i in range(len(x)):
draw.rectangle([x[i-delta],y[i-delta],x[i-delta],y[i-delta]], fill=(0,255,0))
im.save("your_image.png")
Centaurus_A-DeNoiseAI-denoise.jpg
Cen_A_cropped.jpg
Your post-processing logic is flawed. You remove a bunch of X values in the range 1110-1977, without checking whether its corresponding Y value is also in the range of the box. Remove this code section instead and add that logic the first time you loop to gather your x and y coords.
for count in range(width):
for i in range(height):
X,Y = count,i
if 1110 <= X < 1977 and 1069 <= Y < 1905: # add these
continue # two lines
(R,G,B) = imag.getpixel((X,Y))
However, there is a better way of doing the exact same thing by using numpy arrays. Instead of writing explicit loops, you can vectorise a lot of your computations.
import numpy as np
from PIL import Image, ImageDraw
image = Image.open('Centaurus_A-DeNoiseAI-denoise.jpg').convert('RGB')
img1 = np.array(image)
img2 = np.array(Image.open('Cen_A_cropped.jpg').convert('RGB'))
coeffs = np.array([.299, .587, .114])
average = img2.mean(axis=(0, 1))
brightness_average = np.sqrt(np.sum(average**2 * coeffs))
reference = brightness_average / (calculate_brightness(13050, 15.79,3.7) / 6.84)
print(f'Avg. brightness: {brightness_average}')
print(f'Reference: {reference}')
brightness = np.sqrt(np.sum(img1.astype(int)**2 * coeffs, axis=-1))
accepted_brightness = (brightness >= reference) * (brightness <= reference + 3)
pixels_used = np.ones((img1.shape[:2]), dtype=bool)
pixels_used[1069:1905,1110:1977] = False
rows, cols = np.where(accepted_brightness * pixels_used)
with image as im:
draw = ImageDraw.Draw(im)
draw.point(list(zip(cols, rows)), fill=(0, 255, 0))
image.save('out.png')
The main trick used here is in the line
rows, cols = np.where(accepted_brightness * pixels_used)
accepted_brightess is a 2d array of each pixel with a boolean value whether its brightness is within your preferred range. pixels_used is another 2d boolean array, where every pixel is True, except from the pixels in the box near the centre you want to ignore. The combination of those two gives you the pixel coordinates that have the correct brightness and are not in the square in the centre.

Locate color position on screen?

I want to click on a specific color on the screen with pyautogui, but for that I need its position, and I can't find any useful information about the topic. I'm trying to make a Piano Tiles autoclicker and for that I've thought about identifying the tiles' color and clicking it.
You can find color position with pyautogui:
import pyautogui
color = (255, 255, 255)
s = pyautogui.screenshot()
for x in range(s.width):
for y in range(s.height):
if s.getpixel((x, y)) == color:
pyautogui.click(x, y) # do something here
Consider making a screenshot of smaller area to identify pixels faster.
pyautogui.screenshot(region=(0,0, 300, 400))
The argument is a four-integer tuple of the left, top, width, and height of the region to capture. You can even grab only one pixel of each tile to make it work better. I don't think making a screenshot of the whole screen would be a great idea, especially when tiles goes fast.
How I would do it:
use pyautogui.position() to get coords of one pixel of each region where tiles appears (assuming color of tile is solid and is not changing during the game)
use getpixel() to obtain the RGB values of tile pixel
check in loop if pixels with coordinates from step 1 have the same RGB values you obtained in step 2.
Call pyautogui.click() if yes
Here is another version that counts how many pixels are in the region:
import pyautogui
def checkForRGBValues(start=(0,0), end=(50,50), R=255, G=255, B=255): #start/end/r/g/b value, I put some standard values for testing
x = int(end[0]-start[0] + 1) #calculates x value between start and end
y = int(end[1]-start[1] + 1) #calculates y value between start and end
how_many_pixels_found = 0 #nothing found yet
for x in range(start[0], end[0] + 1, 1): #loops through x value
for y in range(start[1], end[1] + 1, 1): #loops through y value
if pyautogui.pixel(x, y)[0] == R and pyautogui.pixel(x, y)[1] == G and pyautogui.pixel(x, y)[2] == B: #checks if the wanted RGB value is in the region
how_many_pixels_found = how_many_pixels_found + 1 #adds one to the result
y = y + 1
x = x + 1
return how_many_pixels_found #returns the total value of pixels with the wanted color in the region.
x = checkForRGBValues((150,200), (200,250), R=60, G=63, B=65)
print(x)
This is my first post! :) I had the same problem, but I found a solution. My code is probably not following any programming standard, but it is working hahaha! I started programming in Python 2 months ago (some experience 20 years ago (QBasic/C/Java), but never anything professional). Please tell me if is working for you and if there is anything that I can improve. I hope I can help somebody with this post, since this site has been helping me so much in the last 2 months!
def checkForRGBValues(start=(0,0), end=(50,50), R=255, G=255, B=255):
x = int(end[0]-start[0] + 1)
y = int(end[1]-start[1] + 1)
# print(x)
# print(y)
for x in range(start[0], end[0] + 1, 1):
for y in range(start[1], end[1] + 1, 1):
print(str(x) + "/" + str(y))
if pyautogui.pixel(x, y)[0] == R and pyautogui.pixel(x, y)[1] == G and pyautogui.pixel(x, y)[2] == B:
print("Color found")
with open("color_found.txt", "a") as file_found:
file_found.write(str(x) + "/" + str(y))
file_found.write("\n")
else:
with open("color_not_found.txt", "a") as file:
file.write(str(x) + "/" + str(y))
file.write("\n")
y = y + 1
x = x + 1
checkForRGBValues((150,200), (200,250), R=255, G=0, B=0) #if nothing (0,0), (50,50)

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.

QR Code manipulation using Python (jython) - Scaling and removing Quiet Zone

Having trouble with this particular task (using JES 4.3). The task is to scale down a QR code image using Python to a 25 x 25 image, and to remove the white border (quiet zone) from the image. I have no trouble scaling it down, but the removal of the quiet zone is troubling. I believe it must be done before the scaling itself, and the quiet zone width can vary. Thus it appears that I need to remove each outer layer of pixels one by one until the program detects that its no longer the quiet zone. Quite sure a while loop is required, but have no clue how to implement that effectively. My code so far:
def reduce(qrPicture):
file = makePicture(qrPicture)
myPicture = duplicatePicture(file)
width = getWidth(myPicture)
height = getHeight(myPicture)
newPicture = makeEmptyPicture(25, 25)
newWidth = getWidth(newPicture)
newHeight = getHeight(newPicture)
basePixel = getPixelAt(myPicture, 0, 0)
startX = 0
startY = 0
xWidth = width/float(newWidth)
yHeight = height/float(newHeight)
for x in range(startX, newWidth):
for y in range(startY, newHeight):
smallPix = getPixel(newPicture, x, y)
pixelX = x*xWidth;
pixelY = y*yHeight;
oPixel = getPixel(myPicture, int(pixelX), int(pixelY))
setColor(smallPix, getColor(oPixel))
As mentioned, this simply scales the image to 25 x 25 but does not remove the quiet zone. Can someone tell me how to implement this removal of the quiet zone? Thanks.
def findQuietZone(pic):
width = getWidth(pic)
height = getHeight(pic)
for x in range(0, width):
for y in range(0, height):
px = getPixel(pic, x, y)
color = getColor(px)
if (colour != white):
value = getX(px)
quietZone = width - value

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