I want to draw a box around an image where there are black pixels.
this is my image:(quiz.JPG):
and i would like the image to be something like this:
but with the code below I get this(quiz2.JPG):
here is what i have tried:
from PIL import Image,ImageDraw
image = Image.open("quiz.JPG").convert('L') #open and convert to black and white
pixels = image.load()
width, height = image.size
black_pixels= []
for col in range(width):
for row in range(height):
pixel = pixels[col, row]
if pixel == (0): #select pixels that are black
black_pixels.append((col, row)) #add them to the list of black pixels
def sortCoordinates(lst): #this is just a bubble sort to get the coordinates in order of y values
length = len(lst) -1
solved = False
while not solved:
solved = True
for i in range(length):
if lst[i][1] > lst[i+1][1]:
solved = False
lst[i],lst[i+1] = lst[i+1],lst[i]
return lst
black_pixels = sortCoordinates(black_pixels)
def getShape(black_pixels): # function to generate box from the pixels given
firstPixelXValue = black_pixels[0][0]
lastPixelXValue = black_pixels[-1][0]
tallestPixel = 0
for pixel in black_pixels:
YValue = pixel[1]
if YValue > tallestPixel:
tallestPixel = YValue
topMostPixelYValue = tallestPixel
shortestPixel = pixel[1]
for pixel in black_pixels:
YValue = pixel[1]
if YValue < shortestPixel:
shortestPixel = YValue
bottomMostPixelYValue = shortestPixel
shape = [(firstPixelXValue-4, topMostPixelYValue+2), (lastPixelXValue+4,bottomMostPixelYValue-3)]
return shape
questions = {}
count = 0
count2 = 0
currentQuestionPixels = []
oldPixelY = black_pixels[0][1]
for newPixel in black_pixels:
newPixelY = newPixel[1]
if newPixelY > oldPixelY + 100 or len(black_pixels)-1 == count2: #run this if new question is found
questions[str(count)] = getShape(currentQuestionPixels)
currentQuestionPixels = []
count += 1
oldPixelY = newPixelY
currentQuestionPixels.append(newPixel)
count2 += 1
image = image.convert('RGB')
for question in questions: #draw shape around all questions found
shape = questions.get(question)
img1 = ImageDraw.Draw(image)
img1.rectangle(shape, outline ="red")
image.save("quiz2.JPG")
This should work, in theory, because I am getting all the black pixel coordinates and sorting them out into their Y values. Then I am looping through the black pixels and if the new pixel Y value is grater than the old pixel Y value + 100 or it is the last pixel it must be a new question.
So then I draw a box around all the questions
I've modified the getShape function
Check out the code below
from PIL import Image,ImageDraw
image = Image.open("quiz.JPG").convert('L') #open and convert to black and white
pixels = image.load()
width, height = image.size
black_pixels= []
for col in range(width):
for row in range(height):
pixel = pixels[col, row]
if pixel == (0): #select pixels that are black
black_pixels.append((col, row)) #add them to the list of black pixels
def sortCoordinates(lst): #this is just a bubble sort to get the coordinates in order of y values
length = len(lst) -1
solved = False
while not solved:
solved = True
for i in range(length):
if lst[i][1] > lst[i+1][1]:
solved = False
lst[i],lst[i+1] = lst[i+1],lst[i]
return lst
black_pixels = sortCoordinates(black_pixels)
def getShape(black_pixels): # function to generate box from the pixels given
first_x = 0
first_y = 0
last_x = 99999999
last_y = 99999999
for x, y in black_pixels:
if first_x < x :
first_x = x
if first_y < y :
first_y = y
if last_x > x :
last_x = x
if last_y > y :
last_y = y
shape = [(first_x-4, first_y+2), (last_x+4,last_y-3)]
return shape
questions = {}
count = 0
count2 = 0
currentQuestionPixels = []
oldPixelY = black_pixels[0][1]
for newPixel in black_pixels:
newPixelY = newPixel[1]
if newPixelY > oldPixelY + 100 or len(black_pixels)-1 == count2: #run this if new question is found
questions[str(count)] = getShape(currentQuestionPixels)
currentQuestionPixels = []
count += 1
oldPixelY = newPixelY
currentQuestionPixels.append(newPixel)
# print(currentQuestionPixels)
count2 += 1
image = image.convert('RGB')
for question in questions: #draw shape around all questions found
shape = questions.get(question)
print(shape)
img1 = ImageDraw.Draw(image)
img1.rectangle(shape, outline ="red")
image.save("quiz2.JPG")
Related
while testing the gradient vector field (gvf) with a single image, I used the an input image to get the threshold image with seed, but got stuck with the error list object has no attribute astype. I'm using google co lab. Any help and thanks in advance. I got an error at the line write_mask8([pair[i]], "pair_raw", i).
global th
global newimg
global pairtype here
# Nuclei center detection
gvf = GVF(images, th)
dismap = gvf.distancemap()
newimg = gvf.new_image(0.4, dismap) # choose alpha as 0.4.
gradimg = gvf.compute_gvf(newimg)
out = []
pair = []
pair_raw = []
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
i = 0
for i,img in enumerate(gradimg):
imgpair_raw = gvf.find_certer(img, i)
pair_raw.append(imgpair_raw)
neighborhood_size = 20
data_max = ndimage.filters.maximum_filter(pair_raw[i], neighborhood_size)
data_max[data_max==0] = 255
pair.append((pair_raw[i] == data_max).astype(np.uint8))
write_mask8([pair[i]], "pair_raw", i)
os.chdir(".")
y, x = np.where(pair[i]>0)
#points = zip(y[:], x[:])
points = np.vstack((y, x)).T
dmap = distance.cdist(points, points, 'euclidean')
y, x = np.where(dmap<10)
ps = zip(y[:], x[:])
for p in ps:
if p[0] != p[1]:
pair[i][points[min(p[0], p[1])]] = 0
dilation = cv2.dilate((pair[i]*255).astype(np.uint8),kernel,iterations = 3)
out.append(dilation)
out = cvt_npimg(out)
vis_square(out)
where mask_8 is defined as:
def write_mask8(images, name, index=-1):
"""
Write image as 8 bits image
"""
if index == -1:
for i, img in enumerate(images):
if i < 10:
cv2.imwrite(name+"00"+str(i)+".tif", img.astype(np.uint8))
elif i >= 10 and i < 100:
cv2.imwrite(name+"0"+str(i)+".tif", img.astype(np.uint8))
else:
cv2.imwrite(name+str(i)+".tif", img.astype(np.uint8))
else:
if index < 10:
cv2.imwrite(name+"000"+str(index)+".tif", images.astype(np.uint8))
elif index >= 10 and index < 100:
cv2.imwrite(name+"00"+str(index)+".tif", images.astype(np.uint8))
elif index >= 100 and index < 1000:
cv2.imwrite(name+"0"+str(index)+".tif", images.astype(np.uint8))
elif index >= 1000 and index < 10000:
cv2.imwrite(name+str(index)+".tif", images.astype(np.uint8))
else:
raise
I had images that were in tiles of the following format:
Each number represents a single tile. I used the following script (with the help of stackoverflow) and stitched the images together. The following is the script that I used to stitch the images together:
from PIL import Image
import os
path_to_file ='tiff-files'
def stich_tile(path_to_file, xx , yy):
images = []
for i in os.listdir(path_to_file):
images.append(i)
if len(images) >= xx*yy:
pass
else:
raise ValueError('not enough images in path_to_file !!!!!!!!!!!')
sq_x = xx
sq_y = yy
img_x = (Image.open(path_to_file+'/'+images[0]).size[0])
img_y = (Image.open(path_to_file+'/'+images[0]).size[1])
img_mode = (Image.open(path_to_file+'/'+images[0]).mode)
new_image = Image.new(img_mode, (img_x*sq_x, img_y*sq_y))
x = 0
y = 0
cnt = 0
for i in images:
with Image.open(path_to_file+'/'+i) as img:
new_image.paste(img, (x,y))
cnt += 1
x += img_x
if cnt == sq_x:
x = 0
y += img_y
cnt = 0
else:
pass
return new_image
stich_tile(path_to_file, 3, 5).save('filename.tiff')
The output saved image looks like the following:
I would like to remove the black image that was created. How do I do that?
here modified script that removes black border from bottom and right of the stitched images... as long as the problem was within the starting images:
import numpy as np
from PIL import Image
import os
# path_to_file ='tiff-files'
# path_to_file ='tiff-files2'
# path_to_file ='tiff-files3'
# path_to_file ='tiff-files5'
# path_to_file ='tiff-files5'
path_to_file ='tiff-files6'
def stich_tile(path_to_file, xx , yy):
images = []
for i in os.listdir(path_to_file):
images.append(i)
images.sort() # sort images alphabetically
# images.sort(key = lambda x: int(x.strip('.tiff').split('-')[1])) ## ---> per path_to_file ='tiff-files3'
images = images[:xx*yy] #-----> riduce lista immagini al numero richiesto
print(images)
print('lenght list of images', len(images), 'x and y requested', xx*yy)
if len(images) >= xx*yy:
pass
else:
# raise ValueError('not enough images in path_to_file !!!!!!!!!!!')
raise ValueError('EXCEPTION not enough images in path_to_file !!!!!!!!!!!', xx*yy,'images needed : ', len(images),'images present !!!')
sq_x = xx
sq_y = yy
img_x = (Image.open(path_to_file+'/'+images[0]).size[0])
img_y = (Image.open(path_to_file+'/'+images[0]).size[1])
img_mode = (Image.open(path_to_file+'/'+images[0]).mode)
print('images[0] size : ', img_x, img_y, img_x*sq_x, img_y*sq_y)
new_image = Image.new(img_mode, (img_x*sq_x, img_y*sq_y))
print('new_image : size :', new_image.size)
x = 0
y = 0
cnt = 0
cnt_cycle = 0
for i in images:
with Image.open(path_to_file+'/'+i) as img:
new_image.paste(img, (x,y))
cnt += 1
cnt_cycle += 1
x += img_x
if cnt == sq_x:
x = 0
y += img_y
cnt = 0
else:
pass
print('count of for i in images cycles', cnt_cycle)
new_image = np.array(new_image)
print(new_image.shape, np.min(new_image), np.max(new_image))
for ar_y in range(new_image.shape[0]-1,0,-1):
res = np.all(new_image[ar_y,:] == (0,0,0))
if res:
new_image = new_image[0:(ar_y),:]
# print('black', ar_y)
else:
print('break at :', ar_y ,' row')
break
print(new_image.shape, np.min(new_image), np.max(new_image))
print(new_image.shape, np.min(new_image), np.max(new_image))
for ar_x in range(new_image.shape[1]-1,0,-1):
res = np.all(new_image[:,ar_x] == (0,0,0))
if res:
new_image = new_image[:,0:(ar_x)]
# print('black', ar_x)
else:
print('break at :', ar_x ,' column')
break
print(new_image.shape, np.min(new_image), np.max(new_image))
new_image = Image.fromarray(new_image)
return new_image
try :
pippo = stich_tile(path_to_file, 3,3)
pippo.show()
# pippo.save('RGB_black_tiff_3X.tiff')
except ValueError as err:
print('stopped', err.args)
could use same approach to remove black border from top/left.
Could be that pillow library has an in built option/function/whatever its called to do the same....
its kind of late here, tested code with 3X3 RGB tiff images with black borders.. let me know if it works
I have a typical captcha image which contain only digits.
Ex.
i want to extract 78614 from this image.
I tried few library & code using OCR-Python. But its returning 0.
Sample Code-1
from captcha_solver import CaptchaSolver
solver = CaptchaSolver('browser')
with open('captcha.png', 'rb') as inp:
raw_data = inp.read()
print(solver.solve_captcha(raw_data))
Sample Code-2
from PIL import Image
def p(img, letter):
A = img.load()
B = letter.load()
mx = 1000000
max_x = 0
x = 0
for x in range(img.size[0] - letter.size[0]):
_sum = 0
for i in range(letter.size[0]):
for j in range(letter.size[1]):
_sum = _sum + abs(A[x+i, j][0] - B[i, j][0])
if _sum < mx :
mx = _sum
max_x = x
return mx, max_x
def ocr(im, threshold=200, alphabet="0123456789abcdef"):
img = Image.open(im)
img = img.convert("RGB")
box = (8, 8, 58, 18)
img = img.crop(box)
pixdata = img.load()
letters = Image.open(im)
ledata = letters.load()
# Clean the background noise, if color != white, then set to black.
for y in range(img.size[1]):
for x in range(img.size[0]):
if (pixdata[x, y][0] > threshold) \
and (pixdata[x, y][1] > threshold) \
and (pixdata[x, y][2] > threshold):
pixdata[x, y] = (255, 255, 255, 255)
else:
pixdata[x, y] = (0, 0, 0, 255)
counter = 0;
old_x = -1;
letterlist = []
for x in range(letters.size[0]):
black = True
for y in range(letters.size[1]):
if ledata[x, y][0] <> 0 :
black = False
break
if black :
if True :
box = (old_x + 1, 0, x, 10)
letter = letters.crop(box)
t = p(img, letter);
print counter, x, t
letterlist.append((t[0], alphabet[counter], t[1]))
old_x = x
counter += 1
box = (old_x + 1, 0, 140, 10)
letter = letters.crop(box)
t = p(img, letter)
letterlist.append((t[0], alphabet[counter], t[1]))
t = sorted(letterlist)
t = t[0:5] # 5-letter captcha
final = sorted(t, key=lambda e: e[2])
answer = ""
for l in final:
answer = answer + l[1]
return answer
print(ocr('captcha.png'))
Has anyone had the opportunity to get/extract text from such typical captcha?
You can use machine learning (neural networks) models to solve captchas and it will almost always outperform free OCR or any other method.
Here is a good starting point: https://medium.com/#ageitgey/how-to-break-a-captcha-system-in-15-minutes-with-machine-learning-dbebb035a710
I am in my first programming class so very new. I'm trying to count the black pixels in a picture and I'm stuck. This is what I have so far:
def main():
#create a 10x10 black picture
newPict = makeEmptyPicture(10, 10)
show(newPict)
setAllPixelsToAColor(newPict,black)
#Display the picture
show(newPict)
#Initialize variabl countBlack to 0
countZero = 0
for p in getPixels(newPict):
r = getRed(p)
b = getBlue(p)
g = getGreen(p)
if (r,g,b) == (0,0,0):
countZero = countZero + 100
return countZero
How it was pointed by kedar and deets , your return is INSIDE the for, so, in the first pixel it will return the value of countZero, instead of looping over all the image, just fixing the indention should be fine :
for p in getPixels(newPict):
r = getRed(p)
b = getBlue(p)
g = getGreen(p)
if (r,g,b) == (0,0,0):
countZero = countZero + 1
return countZero
I want to create a hexagonal grid using XYZ coordinates that is constructed in a spiraling pattern. This is my current code, which produces a grid depicted by the red arrows below. My problem area is circled. Rather than going from [-1,0,1] to [0,-2,2] I need to move from [-1,0,1] to [-1,-1,2] (following the blue line).
The complete code appears below the hash line- I am creating the visualization in Blender 2.65a
radius = 11 # determines size of field
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
hex_coords = []
for r in range(radius):
x = 0
y = -r
z = +r
points = x,y,z
hex_coords.append(points)
for j in range(6):
if j==5:
num_of_hexas_in_edge = r-1
else:
num_of_hexas_in_edge = r
for i in range(num_of_hexas_in_edge):
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
plot = x,y,z
hex_coords.append(plot)
-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
import bpy
FOXP2 = '''
CTTGAACCTTTGTCACCCCTCACGTTGCACACCAAAGACATACCCTAGTGATTAAATGCTGATTTTGTGT
ACGATTGTCCACGGACGCCAAAACAATCACAGAGCTGCTTGATTTGTTTTAATTACCAGCACAAAATGCC
CAATTCCTCCTCGACTACCTCCTCCAACACTTCCAAAGCATCACCACCAATAACTCATCATTCCATAGTG
AATGGACAGTCTTCAGTTCTAAGTGCAAGACGAGACAGCTCGTCACATGAGGAGACTGGGGCCTCTCACA
CTCTCTATGGCCATGGAGTTTGCAAATGGCCAGGCTGTGAAAGCATTTGTGAAGATTTTGGACAGTTTTT
AAAGCACCTTAACAATGAACACGCATTGGATGACCGAAGCACTGCTCAGTGTCGAGTGCAAATGCAGGTG
GTGCAACAGTTAGAAATACAGCTTTCTAAAGAACGCGAACGTCTTCAAGCAATGATGACCCACTTGCACA
'''
set_size = len(FOXP2)
def makeMaterial(name, diffuse, specular, alpha):
mat = bpy.data.materials.new(name)
mat.diffuse_color = diffuse
mat.diffuse_shader = 'LAMBERT'
mat.diffuse_intensity = 1.0
mat.specular_color = specular
mat.specular_shader = 'COOKTORR'
mat.specular_intensity = 0.5
mat.alpha = alpha
mat.ambient = 1
return mat
def setMaterial(ob, mat):
me = ob.data
me.materials.append(mat)
# Create four materials
red = makeMaterial('Red', (1,0,0), (0,0,0), .5)
blue = makeMaterial('BlueSemi', (0,0,1), (0,0,0), 0.5)
green = makeMaterial('Green',(0,1,0), (0,0,0), 0.5)
yellow = makeMaterial('Yellow',(1,1,0), (0,0,0), 0.5)
black = makeMaterial('Black',(0,0,0), (0,0,0), 0.5)
white = makeMaterial('White',(1,1,1), (0,0,0), 0.5)
def make_sphere(volume, position):
create = bpy.ops.mesh.primitive_uv_sphere_add
create(size=volume, location=position)
# Builds a list of coordinate points
radius = 11
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
hex_coords = []
for r in range(radius):
x = 0
y = -r
z = +r
points = x,y,z
hex_coords.append(points)
for j in range(6):
if j==5:
num_of_hexas_in_edge = r-1
else:
num_of_hexas_in_edge = r
for i in range(num_of_hexas_in_edge):
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
plot = x,y,z
hex_coords.append(plot)
# Color-codes sequence and appends to color_array
color_array = []
for x in FOXP2:
if x == 'A':
color_array.append(1)
elif x == 'T':
color_array.append(1)
elif x == 'C':
color_array.append(0)
elif x == 'G':
color_array.append(0)
else:
pass
# Pulls from sequence data and applies color to sphere
# Positions sphere to coordinates
# Pulls from color_code and applies color scheme to sphere object
for x in color_array:
if x =='RED':
coord_tuple = hex_coords.pop(0)
make_sphere(1, coord_tuple)
setMaterial(bpy.context.object, red)
elif x =='GREEN':
coord_tuple = hex_coords.pop(0)
make_sphere(1, coord_tuple)
setMaterial(bpy.context.object, green)
elif x =='BLUE':
coord_tuple = hex_coords.pop(0)
make_sphere(1, coord_tuple)
setMaterial(bpy.context.object, blue)
elif x =='YELLOW':
coord_tuple = hex_coords.pop(0)
make_sphere(1, coord_tuple)
setMaterial(bpy.context.object, yellow)
else:
pass