aro*_*han 4 python image-processing image-segmentation python-imaging-library
我使用python和PIL在640x480图像中找到各种矩形(和正方形)的质心和旋转,类似于这个 
到目前为止,我的代码适用于图像中的单个矩形.
import Image, math
def find_centroid(im):
width, height = im.size
XX, YY, count = 0, 0, 0
for x in xrange(0, width, 1):
for y in xrange(0, height, 1):
if im.getpixel((x, y)) == 0:
XX += x
YY += y
count += 1
return XX/count, YY/count
#Top Left Vertex
def find_vertex1(im):
width, height = im.size
for y in xrange(0, height, 1):
for x in xrange (0, width, 1):
if im.getpixel((x, y)) == 0:
X1=x
Y1=y
return X1, Y1
#Bottom Left Vertex
def find_vertex2(im):
width, height = im.size
for x in xrange(0, width, 1):
for y in xrange (height-1, 0, -1):
if im.getpixel((x, y)) == 0:
X2=x
Y2=y
return X2, Y2
#Top Right Vertex
def find_vertex3(im):
width, height = im.size
for x in xrange(width-1, 0, -1):
for y in xrange (0, height, 1):
if im.getpixel((x, y)) == 0:
X3=x
Y3=y
return X3, Y3
#Bottom Right Vertex
def find_vertex4 (im):
width, height = im.size
for y in xrange(height-1, 0, -1):
for x in xrange (width-1, 0, -1):
if im.getpixel((x, y)) == 0:
X4=x
Y4=y
return X4, Y4
def find_angle (V1, V2, direction):
side1=math.sqrt(((V1[0]-V2[0])**2))
side2=math.sqrt(((V1[1]-V2[1])**2))
if direction == 0:
return math.degrees(math.atan(side2/side1)), 'Clockwise'
return 90-math.degrees(math.atan(side2/side1)), 'Counter Clockwise'
#Find direction of Rotation; 0 = CW, 1 = CCW
def find_direction (vertices, C):
high=480
for i in range (0,4):
if vertices[i][1]<high:
high = vertices[i][1]
index = i
if vertices[index][0]<C[0]:
return 0
return 1
def main():
im = Image.open('hopperrotated2.png')
im = im.convert('1') # convert image to black and white
print 'Centroid ', find_centroid(im)
print 'Top Left ', find_vertex1 (im)
print 'Bottom Left ', find_vertex2 (im)
print 'Top Right', find_vertex3 (im)
print 'Bottom Right ', find_vertex4 (im)
C = find_centroid (im)
V1 = find_vertex1 (im)
V2 = find_vertex3 (im)
V3 = find_vertex2 (im)
V4 = find_vertex4 (im)
vertices = [V1,V2,V3,V4]
direction = find_direction(vertices, C)
print 'angle: ', find_angle(V1,V2,direction)
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
我遇到问题的地方是图像中有多个物体.
我知道PIL有一个find_edges方法,它只提供边缘的图像,但我不知道如何使用这个新的边缘图像将图像分割成单独的对象.
from PIL import Image, ImageFilter
im = Image.open('hopperrotated2.png')
im1 = im.filter(ImageFilter.FIND_EDGES)
im1 = im1.convert('1')
print im1
im1.save("EDGES.jpg")
Run Code Online (Sandbox Code Playgroud)
如果我可以使用边缘将图像分割成单独的矩形,那么我可以在每个矩形上运行我的第一个代码来获得质心和旋转.
但更好的是能够使用边缘来计算每个矩形的旋转和质心,而无需向上分割图像.
非常感谢大家的帮助!
您需要在找到角落之前识别每个对象.您只需要对象的边框,因此您也可以减少初始输入.然后只需要跟踪每个不同的边界来找到你的角落,在你知道每个不同的边界后直接找到质心.
使用下面的代码,这里是你得到的(质心是红点,白色文本是以度为单位的旋转):

请注意,您的输入不是二进制,因此我使用了一个非常简单的阈值.此外,以下代码是实现此目的的最简单方法,任何体面的库中都有更快的方法.
import sys
import math
from PIL import Image, ImageOps, ImageDraw
orig = ImageOps.grayscale(Image.open(sys.argv[1]))
orig_bin = orig.point(lambda x: 0 if x < 128 else 255)
im = orig_bin.load()
border = Image.new('1', orig.size, 'white')
width, height = orig.size
bim = border.load()
# Keep only border points
for x in xrange(width):
for y in xrange(height):
if im[x, y] == 255:
continue
if im[x+1, y] or im[x-1, y] or im[x, y+1] or im[x, y-1]:
bim[x, y] = 0
else:
bim[x, y] = 255
# Find each border (the trivial dummy way).
def follow_border(im, x, y, used):
work = [(x, y)]
border = []
while work:
x, y = work.pop()
used.add((x, y))
border.append((x, y))
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1),
(1, 1), (-1, -1), (1, -1), (-1, 1)):
px, py = x + dx, y + dy
if im[px, py] == 255 or (px, py) in used:
continue
work.append((px, py))
return border
used = set()
border = []
for x in xrange(width):
for y in xrange(height):
if bim[x, y] == 255 or (x, y) in used:
continue
b = follow_border(bim, x, y, used)
border.append(b)
# Find the corners and centroid of each rectangle.
rectangle = []
for b in border:
xmin, xmax, ymin, ymax = width, 0, height, 0
mean_x, mean_y = 0, 0
b = sorted(b)
top_left, bottom_right = b[0], b[-1]
for x, y in b:
mean_x += x
mean_y += y
centroid = (mean_x / float(len(b)), mean_y / float(len(b)))
b = sorted(b, key=lambda x: x[1])
curr = 0
while b[curr][1] == b[curr + 1][1]:
curr += 1
top_right = b[curr]
curr = len(b) - 1
while b[curr][1] == b[curr - 1][1]:
curr -= 1
bottom_left = b[curr]
rectangle.append([
[top_left, top_right, bottom_right, bottom_left], centroid])
result = orig.convert('RGB')
draw = ImageDraw.Draw(result)
for corner, centroid in rectangle:
draw.line(corner + [corner[0]], fill='red', width=2)
cx, cy = centroid
draw.ellipse((cx - 2, cy - 2, cx + 2, cy + 2), fill='red')
rotation = math.atan2(corner[0][1] - corner[1][1],
corner[1][0] - corner[0][0])
rdeg = math.degrees(rotation)
draw.text((cx + 10, cy), text='%.2f' % rdeg)
result.save(sys.argv[2])
Run Code Online (Sandbox Code Playgroud)