如何用Python与OpenCV提取加油站价格牌的油价信息
加油站价格牌信息提取方案
针对你遇到的价格牌区域定位问题,这里提供一套基于OpenCV的完整实现方案,核心思路是先通过颜色掩码+形态学操作精准定位价格牌,再利用油品对应颜色方块区分品类,最后提取价格(可结合OCR完成数字识别)。
一、核心步骤
- 定位价格牌区域:通过HSV颜色空间筛选价格牌底色,结合形态学操作去除噪点,提取最大轮廓作为价格牌ROI(感兴趣区域)。
- 区分油品类型:提取价格左侧颜色方块的平均颜色,匹配国内标准(绿=汽油、黑=柴油、黄=LPG)。
- 提取与识别价格:分割价格区域,后续可接入OCR工具完成数字识别(示例中模拟输出结果)。
二、完整代码
import cv2 import numpy as np def get_price_board_roi(src_img): # 转换为HSV颜色空间,更适合颜色筛选 hsv = cv2.cvtColor(src_img, cv2.COLOR_BGR2HSV) # 定义价格牌底色的HSV范围(适配示例中的白色底色,可根据实际图片调整) lower_bound = np.array([0, 0, 200]) upper_bound = np.array([180, 30, 255]) mask = cv2.inRange(hsv, lower_bound, upper_bound) # 形态学闭运算:先膨胀再腐蚀,消除小噪点 kernel = np.ones((5, 5), np.uint8) mask_clean = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找轮廓并按面积排序,取最大的轮廓(即价格牌) contours, _ = cv2.findContours(mask_clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours_sorted = sorted(contours, key=cv2.contourArea, reverse=True) board_rect = cv2.boundingRect(contours_sorted[0]) x, y, w, h = board_rect # 提取价格牌ROI return src_img[y:y+h, x:x+w] def judge_fuel_type(color_block): # 计算颜色区域的平均BGR值 avg_b, avg_g, avg_r = np.mean(color_block, axis=(0, 1)) # 匹配国内油品颜色标准 if avg_g > avg_r and avg_g > avg_b: return "95号汽油" elif avg_b < 50 and avg_g < 50 and avg_r < 50: return "柴油" elif avg_r > avg_g and avg_g > avg_b: return "液化石油气(LPG)" return "未知油品" def extract_price_info(board_roi): # 转换为灰度图并做反向阈值处理,突出白色数字 gray = cv2.cvtColor(board_roi, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) # 查找数字轮廓 contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按y坐标排序,保证从上到下处理条目 contours_sorted = sorted(contours, key=lambda c: cv2.boundingRect(c)[1]) price_results = [] for cnt in contours_sorted: x, y, w, h = cv2.boundingRect(cnt) # 过滤小轮廓(噪点) if w < 20 or h < 20: continue # 定位价格左侧的颜色方块(根据实际布局调整偏移量) color_block_x = x - 50 if color_block_x > 0: color_area = board_roi[y:y+h, color_block_x:color_block_x+30] fuel_type = judge_fuel_type(color_area) # 这里模拟OCR识别结果,实际可替换为Tesseract等工具的识别输出 if fuel_type == "柴油": price = "32.20" elif fuel_type == "95号汽油": price = "32.20" elif fuel_type == "液化石油气(LPG)": price = "13.90" price_results.append(f"{fuel_type} - {price}") return price_results # 主执行流程 if __name__ == "__main__": # 读取图片 original_img = cv2.imread("media/totem1.jpeg") # 提取价格牌ROI board_roi = get_price_board_roi(original_img) # 获取价格信息 price_list = extract_price_info(board_roi) # 输出结果 print("提取到的油价信息:") for item in price_list: print(f"- {item}") # 显示处理后的价格牌(可选) cv2.imshow("Price Board ROI", board_roi) cv2.waitKey(0) cv2.destroyAllWindows()
三、关键优化说明
- HSV颜色筛选:相比RGB,HSV对光照变化的鲁棒性更强,能更精准定位价格牌底色。
- 形态学操作:闭运算有效消除图片中的小噪点,避免误识别无关轮廓。
- 轮廓排序:按y坐标排序保证油品条目从上到下的顺序正确,匹配价格牌的布局。
- 颜色平均判断:取颜色方块的平均颜色而非单个像素,避免局部色差影响判断。
四、后续提升建议
- 数字识别:建议使用
pytesseract(Tesseract OCR)替代模拟输出,识别准确率更高,需提前安装Tesseract引擎和pytesseract库。 - 自适应阈值:可改用
cv2.adaptiveThreshold处理光照不均的图片,进一步提升阈值处理效果。 - 透视矫正:如果价格牌存在倾斜,可通过透视变换矫正后再进行区域提取,优化后续识别效果。
内容的提问来源于stack exchange,提问作者opth
相关产品推荐
相关产品推荐

