手写cv2.findContours
时间: 2023-11-11 18:57:49 浏览: 43
cv2.findContours函数用于在图像中查找轮廓。它接受一个二值化图像作为输入,并返回一组轮廓的坐标。
函数的语法如下:
contours, hierarchy = cv2.findContours(image, mode, method)
参数说明:
- image:输入的二值化图像,通常为灰度图像或二值图像。
- mode:轮廓检索模式。有四种模式可选:
- cv2.RETR_EXTERNAL:只检测外部轮廓。
- cv2.RETR_LIST:检测所有轮廓并存储在列表中。
- cv2.RETR_CCOMP:检测所有轮廓并将它们组织为两级层次结构。
- cv2.RETR_TREE:检测所有轮廓并完整地组织为层次结构。
- method:轮廓逼近方法。有三种方法可选:
- cv2.CHAIN_APPROX_NONE:保存所有的轮廓点。
- cv2.CHAIN_APPROX_SIMPLE:仅保存水平、垂直和对角线转折点,压缩水平、垂直和斜线段,即对具有相同颜色的连续部分只保留起点和终点。
- cv2.CHAIN_APPROX_TC89_L1和cv2.CHAIN_APPROX_TC89_KCOS:应用Teh-Chin链逼近算法。
返回值:
- contours:检测到的轮廓,每个轮廓是一个点的列表。
- hierarchy:轮廓的层次结构信息。
相关问题
import cv2 from skimage.feature import hog from sklearn.neighbors import KNeighborsClassifier import joblib import numpy as np # 加载已经训练好的分类器 model_location = "C:/Users/27745/数字图像处理/knn.pkl" knn = joblib.load(model_location) def predict_digit(image): #获取一幅手写数字图像的输入,返回预测结果 # 将图像转换为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 应用高斯模糊和大津二值化来预处理图像 blur = cv2.GaussianBlur(gray, (5, 5), 0) _, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # Find the contours and sort them largest-to-smallest contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=lambda ctr: cv2.boundingRect(ctr)[0]) # 提取每个字符的 ROI 并使用 HOG 特征提取方法进行特征提取 features = [] for cnt in contours: (x, y, w, h) = cv2.boundingRect(cnt) # 添加一定的边框,避免过小的ROI被压缩过多而失去特征 border_size = 20 roi = thresh[max(y - border_size, 0):min(y + h + border_size, image.shape[0]), max(x - border_size, 0):min(x + w + border_size, image.shape[1])] # 将ROI调整为28x28大小,并根据特征提取器生成的HOG描述符提取特征 resized_roi = cv2.resize(roi, (28, 28), interpolation=cv2.INTER_AREA) fd = hog(resized_roi, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys') features.append(fd.reshape(-1, 1)) # 将提取的特征向量输入KNN模型进行预测 results = knn.predict(np.hstack(features)) # 返回数字串预测结果 return ''.join(str(result) for result in results) # 载入测试图片并进行预测 image_name = "C:/Users/27745/Desktop/test1.png" image = cv2.imread(image_name) # 将目标图像统一调整为相同的大小 image = cv2.resize(image, (300, 300)) # 利用封装的函数进行预测 result = predict_digit(image) print("The number is:", result)以上代码出现了X has 216 features, but KNeighborsClassifier is expecting 784 features as input.的问题,请帮我更正
这个错误是因为在特征提取时,使用的HOG特征提取方法生成的特征向量维度不正确。
在代码中,我们将每个字符的ROI调整为28x28大小,并使用HOG特征提取方法生成的特征向量进行特征提取,但是在生成特征向量时,我们使用了`reshape(-1,1)`将特征向量转换为列向量,这导致特征向量的维度不正确。
要解决这个问题,我们需要使用`reshape(1,-1)`将特征向量转换为行向量,这样就可以将特征向量的维度调整为784,与KNN模型期望的输入维度相匹配。
修改代码如下:
```python
# 将ROI调整为28x28大小,并根据特征提取器生成的HOG描述符提取特征
resized_roi = cv2.resize(roi, (28, 28), interpolation=cv2.INTER_AREA)
fd = hog(resized_roi, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys')
features.append(fd.reshape(1, -1)) # 将特征向量转换为行向量
```
这样就可以解决这个问题了。
from tkinter import * import cv2 import numpy as np from PIL import ImageGrab from tensorflow.keras.models import load_model from temp import * model = load_model('mnist.h5') image_folder = "img/" root = Tk() root.resizable(0, 0) root.title("HDR") lastx, lasty = None, None image_number = 0 cv = Canvas(root, width=1200, height=480, bg='white') cv.grid(row=0, column=0, pady=2, sticky=W, columnspan=2) def clear_widget(): global cv cv.delete('all') def draw_lines(event): global lastx, lasty x, y = event.x, event.y cv.create_line((lastx, lasty, x, y), width=8, fill='black', capstyle=ROUND, smooth=True, splinesteps=12) lastx, lasty = x, y def activate_event(event): global lastx, lasty cv.bind('<B1-Motion>', draw_lines) lastx, lasty = event.x, event.y cv.bind('<Button-1>', activate_event) def Recognize_Digit(): global image_number filename = f'img_{image_number}.png' root.update() widget = cv x = root.winfo_rootx() + widget.winfo_rootx() y = root.winfo_rooty() + widget.winfo_rooty() x1 = x + widget.winfo_width() y1 = y + widget.winfo_height() print(x, y, x1, y1) # get image and save ImageGrab.grab().crop((x, y, x1, y1)).save(image_folder + filename) image = cv2.imread(image_folder + filename, cv2.IMREAD_COLOR) gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY) ret, th = cv2.threshold( gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # contours = cv2.findContours( # th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] Position = findContours(th) for m in range(len(Position)): # make a rectangle box around each curve cv2.rectangle(th, (Position[m][0], Position[m][1]), ( Position[m][2], Position[m][3]), (255, 0, 0), 1) # Cropping out the digit from the image corresponding to the current contours in the for loop digit = th[Position[m][1]:Position[m] [3], Position[m][0]:Position[m][2]] # Resizing that digit to (18, 18) resized_digit = cv2.resize(digit, (18, 18)) # Padding the digit with 5 pixels of black color (zeros) in each side to finally produce the image of (28, 28) padded_digit = np.pad(resized_digit, ((5, 5), (5, 5)), "constant", constant_values=0) digit = padded_digit.reshape(1, 28, 28, 1) digit = digit / 255.0 pred = model.predict([digit])[0] final_pred = np.argmax(pred) data = str(final_pred) + ' ' + str(int(max(pred) * 100)) + '%' print(data) font = cv2.FONT_HERSHEY_SIMPLEX fontScale = 0.5 color = (255, 0, 0) thickness = 1 cv2.putText(th, data, (Position[m][0], Position[m][1] - 5), font, fontScale, color, thickness) cv2.imshow('image', th) cv2.waitKey(0) cv2.destroyAllWindows() btn_save = Button(text='Recognize Digit', command=Recognize_Digit) btn_save.grid(row=2, column=0, pady=1, padx=1) button_clear = Button(text='Clear Widget', command=clear_widget) button_clear.grid(row=2, column=1, pady=1, padx=1) root.mainloop()
这段代码是一个Python程序,用于画图并识别手写数字。它调用了许多库,如tkinter、cv2、numpy、PIL和tensorflow。程序创建了一个图形用户界面,包括一个白色的画布和一个按钮。用户在画布上绘制数字后,可以点击按钮来触发识别数字的功能。程序会将绘制的数字保存为图片文件,并加载训练好的模型(mnist.h5)来识别数字。程序最后打印出保存的图片文件的坐标信息。