備忘錄_20160105(定位)
修改
回首頁
程式 2025-11-05 15:41:36 1762328496 100
辨識藥品顆粒並圈出來
辨識藥品顆粒並圈出來
count.py
import cv2
import time
from datetime import datetime
import numpy as np
import sys
import os
import platform
import subprocess
from scipy.stats import norm
def open_image(path):
system = platform.system()
if system == "Windows":
os.startfile(path) # 直接呼叫預設看圖程式
elif system == "Darwin": # macOS
subprocess.run(["open", path])
else: # Linux (例如 Raspberry Pi, Ubuntu)
subprocess.run(["xdg-open", path])
def count_and_draw(in_path, out_path="output.png"):
img = cv2.imread(in_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
ret, thresh = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY) # 手動閥值 200
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 將極端面積的區域去除(極小面積、極大面積)
# 計算一顆藥錠的面積 unit_area
area_list=[]
for i,contour in enumerate(contours):
area = cv2.contourArea(contour)
area_list.append(area)
area_list_sorted=np.sort(area_list)
trim_percent=0.3
n=len(area_list_sorted)
lower_idx=int(n*trim_percent)
upper_idx=int(n*(1-trim_percent))
area_list_trimmed=area_list_sorted[lower_idx:upper_idx]
data=np.array(area_list_trimmed)
unit_area,std=norm.fit(data)
print(area_list_trimmed)
print("unit_area="+str(unit_area))
min_area = unit_area*0.6
max_area = unit_area*1.4
total1=0
total2=0
for i,contour in enumerate(contours):
area = cv2.contourArea(contour)
x, y, w, h = cv2.boundingRect(contour)
if area<min_area:
continue
elif area>max_area:
count_maybe=int(round(area/unit_area,0))
cv2.drawContours(img, [contour], -1, (0,0,255), 2)
cv2.putText(img, str(count_maybe), (int(x+w/2)-10+3, int(y+h/2)+10+3), cv2.FONT_HERSHEY_SIMPLEX, 2, (61,135,38), 5)
cv2.putText(img, str(count_maybe), (int(x+w/2)-10, int(y+h/2)+10), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), 5)
total2=total2+count_maybe
else:
cv2.drawContours(img, [contour], -1, (255,0,0), 2)
total1=total1+1
cv2.putText(img, "1="+str(total1), (30,100), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 0), 4)
cv2.putText(img, "2="+str(total2), (30,150), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 4)
if total1>total2:
cv2.putText(img, "n="+str(total1+total2), (30,200), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 255), 4)
cv2.imwrite(out_path, img)
return total1, total2, out_path
else:
return count_and_draw_advanced(in_path, out_path, unit_area)
def count_and_draw_advanced(in_path, out_path, unit_area_ver1):
img = cv2.imread(in_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
ret, thresh = cv2.threshold(blur, 200, 255, cv2.THRESH_BINARY) # 手動閥值 200
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 將極端面積的區域去除(極小面積、極大面積)
# 計算一顆藥錠的面積 unit_area
area_list=[]
for i,contour in enumerate(contours):
area = cv2.contourArea(contour)
if area>(unit_area_ver1/5) and area<unit_area_ver1:
area_list.append(area)
area_list_sorted=np.sort(area_list)
trim_percent=0.3
n=len(area_list_sorted)
lower_idx=int(n*trim_percent)
upper_idx=int(n*(1-trim_percent))
area_list_trimmed=area_list_sorted[lower_idx:upper_idx]
data=np.array(area_list_trimmed)
unit_area,std=norm.fit(data)
print(area_list_trimmed)
print("unit_area="+str(unit_area))
min_area = unit_area*0.6
max_area = unit_area*1.4
total1=0
total2=0
for i,contour in enumerate(contours):
area = cv2.contourArea(contour)
x, y, w, h = cv2.boundingRect(contour)
if area<min_area:
continue
elif area>max_area:
count_maybe=int(round(area/unit_area,0))
cv2.drawContours(img, [contour], -1, (0,0,255), 2)
cv2.putText(img, str(count_maybe), (int(x+w/2)-10+3, int(y+h/2)+10+3), cv2.FONT_HERSHEY_SIMPLEX, 2, (61,135,38), 5)
cv2.putText(img, str(count_maybe), (int(x+w/2)-10, int(y+h/2)+10), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), 5)
total2=total2+count_maybe
else:
cv2.drawContours(img, [contour], -1, (255,0,0), 2)
total1=total1+1
cv2.putText(img, "1="+str(total1), (30,100), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 0), 4)
cv2.putText(img, "2="+str(total2), (30,150), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 4)
if total2>=total1:
cv2.putText(img, "should be "+str(total1+total2), (30,200), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 255), 4)
else:
cv2.putText(img, "n="+str(total1+total2), (30,200), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 0, 255), 4)
cv2.imwrite(out_path, img)
return total1, total2, out_path
def main(device_index=0, width=1920, height=1080):
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
if not cap.isOpened():
print("無法打開攝影機,請確認 device_index 是否正確或裝置是否連接。")
return
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
scale=0.6
while True:
ret, frame = cap.read()
if not ret:
print("讀取影格失敗,結束。")
break
resized_frame = cv2.resize(frame, (0, 0), fx=scale, fy=scale)
cv2.imshow("Camera", resized_frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'): # 按 q 鍵離開
break
if key == ord(' '): # 空白鍵
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"capture_{timestamp}.jpg"
cv2.imwrite(filename, frame)
print(f"已儲存影像:{filename}")
in_path=filename
out_path=filename.replace('.', '_out.')
total1, total2, out_path = count_and_draw(in_path, out_path)
print(f"Total1:{total1}. Total2:{total2} Result image saved to {out_path}")
if (total1+total2)<1:
result = subprocess.run([sys.executable, "speak_chinese.py", "什麼都沒有喔!"], capture_output=True, text=True)
if total2>=total1:
open_image(out_path)
result = subprocess.run([sys.executable, "speak_chinese.py", "請看一下,藥錠應該是 "+str(total1+total2)+" 顆。"], capture_output=True, text=True)
else:
open_image(out_path)
result = subprocess.run([sys.executable, "speak_chinese.py", "太棒了,你有藥錠 "+str(total1+total2)+" 顆。"], capture_output=True, text=True)
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
# device_index 預設 0;如果有多個攝影機,改成 1, 2, ...
main(device_index=0, width=1920, height=1080)
speak_chinese.py
from gtts import gTTS
from pydub import AudioSegment
from pydub.playback import play
import io
import sys
# windows 7 底下
# pip install gtts
if len(sys.argv) > 1:
received_text = sys.argv[1]
tts = gTTS(text=received_text, lang='zh-tw')
fp = io.BytesIO()
tts.write_to_fp(fp)
fp.seek(0)
audio = AudioSegment.from_file(fp, format="mp3")
play(audio)