主題: 002.01 圖片去外框處理
建檔日期: 2019/08/26
更新日期: None
語言: Python 3.7.4, PIL Pillow 6.1.0., tkinter 8.6
系統: Win10 Ver. 10.0.17763 繁體中文版(TW)
002.01 圖片去外框處理
程式庫的熟練還是要多寫程式, 才會瞭解一些相的使用細節, 下面是有關圖片去外框的處理, 內容不想作的太複雜, 所以有些地方, 並沒有列入考慮.
說明:
1. 去外框的方式是在圖片上, 以滑鼠左鍵點選要去掉的部份的一個點, 尋找附近在顏色誤差範圍內的點, 都改為白色, 可以重複點選處理, 只能回到上一個圖片.
2. 圖檔案的檔名在程式中, 沒作檔案選擇的功能, 也沒加入存檔的功能
3. 圖檔案尺寸太大可能在顯示會超出螢幕, 不在考慮中.
4. 因為使用遞迴呼叫, 圖片太大或太複雜可能會超出遞迴呼叫次數的要求, 僅設為2000次, 有必要可以再加大到數萬次.
5. 因為圖片中的邊緣是以誤差值來界定, 所以簡單的圖片可以設大的誤差值, 一次作到要求, 對於複雜的圖片, 只能一點一點來作.
結果
1. 簡單的圖(顏色簡單, 本體與外圍顏色差距大, 通常一次點選就能完成)
2. 複雜的圖(指的是本體的顏色色與外圍的顏色過於接近, 而且有太多不同的顏色成份, 需經過多次的點選處理)
程式
from tkinter import *
from PIL import Image, ImageTk
class display():
# Canvas的圖片顯示
def __init__(self, widget, imageObj):
self.center = (int(imageObj.width/2), int(imageObj.height/2))
self.photo = ImageTk.PhotoImage(image=imageObj)
self.image = widget.create_image(self.center, image=self.photo)
def check(x0, y0):
# 確認圖點顏色是不要轉換成白點
r, g, b = im.getpixel((x0,y0))
checked[x0][y0] = True
if limit[0][0] <= r <= limit[0][1]:
if limit[1][0] <= g <= limit[1][1]:
if limit[2][0] <= b <= limit[2][1]:
return True
return False
def check_point(x0, y0, new_points):
# 檢查圖點要不要處理
# 超出圖面, 已在要處理清單中, 顏色不對, 或已處理的點, 不處理
if 0<=x0<im.width and 0<=y0<im.height:
if (x0, y0) not in new_points:
if not checked[x0][y0]:
if check(x0,y0):
new_points.append((x0, y0))
def fill(points):
# 處理清單中的點, 還有上下左右四點是否加清單中待處理
global checked, count
count += 1
print('Recursion count :', count)
if points==[]:
return
new_points = []
for point in points:
x = point[0]
y = point[1]
checked[x][y] = True
if check(x, y):
im_new.putpixel((x,y), (255,255,255))
check_point(x-1, y, new_points)
check_point(x+1, y, new_points)
check_point(x, y-1, new_points)
check_point(x, y+1, new_points)
# 待處理清單, 遞迴再處理
points = new_points[:]
fill(points)
def process(event):
global old_x, old_y, click_again, limit, trigger, points, im_new, checked, image01, im_old, im, error, count
# 處理中, 不再處理新事件
if not trigger:
return
trigger = False
# 超出圖片範圍, 改為在圖片範圍
if event.x >= im.width:
x = im.width - 1
else:
x = event.x
if event.y >= im.height:
y = im.height - 1
else:
y = event.y
# 取得圖點顏色, 並設定誤差範圍
r, g, b = im.getpixel((event.x, event.y))
limit = [(r-error, r+error), (g-error, g+error), (b-10, b+error)]
# 設定起點為滑鼠左鍵點選位置
points = [(event.x, event.y)]
# 所有的點都未處理
checked = [[False for i in range(im_new.height)] for j in range(im_new.width)]
# 遞迴次數計算初值
count = 0
# 處理圖片, 並顯示
fill(points)
image01 = display(can01, im_new)
# 只保留前一張原圖
im_old = im.copy()
im = im_new.copy()
# 可再接受新的點選事件
trigger = True
def change_error():
# 輸入誤差值事件
global error
error = int(input('give the error value'))
def undo():
# Undo 回前一張圖片, 只能Undo一次
global im_new, im_old, image01, can01
im_new = im_old.copy()
image01 = display(can01, im_new)
trigger = True
error = 30 # 誤差初值
font = 'times 20 bold'
filename = '5.jpg' # 圖片檔名
im = Image.open(filename)
root = Tk() # 兩個Canvas顯示原圖及新圖+兩個Button功能為設誤差值及Undo
can00 = Canvas(root, bg='green', width=im.width, height=im.height)
can01 = Canvas(root, bg='green', width=im.width, height=im.height)
but10 = Button(root, bg='green', text = 'Set error value', font=font, fg='white', command=change_error)
but11 = Button(root, bg='green', text = 'Undo just one time', font=font, fg='white', command=undo)
can00.grid(row=0, column=0)
can01.grid(row=0, column=1)
but10.grid(row=1, column=0)
but11.grid(row=1, column=1)
# 兩個畫布都可以接受點選
can00.bind('<Button-1>', process)
can01.bind('<Button-1>', process)
im_old = im.copy()
im_new = im.copy()
image00 = display(can00, im)
# 遞迴最大次數
sys.setrecursionlimit(2000)
root.mainloop()