2.13 マウス操作による対象画像のクロップ
実験の目的
-
マウスで選択した 2 つの座標点が形成する矩形をクロップ領域とし、その領域の画像を表示します。
-
マウスイベントに応答して処理できるようになります。
機能要件
マウス操作で対象画像をクロップします。
ハードウェアの準備
| No. | 名称 | 数量 | 備考 |
|---|---|---|---|
| 1 | RDK X5 | 1 | 組み込みメインボード(32GB メモリーカード付き)。上位機(PC 側)システムとして動作します。 |
| 2 | カードリーダー | 1 | システムイメージの書き込みに使用します。 |
| 3 | USB カメラ | 1 | 画像を取得します。 |
| 4 | 電源ケーブル | 1 | 電源供給用です。 |
| 5 | LAN ケーブル | 1 | ネットワーク接続用です。 |
回路接続

ソフトウェア設計
設計フローチャート
ソースコードのダウンロード
ソースコードファイル:13_opencv_cut_img_mouse.rar
プログラムコード
完全なプロジェクトコードは(ソースコードファイル)をクリックしてダウンロードしてください。
"""
---------------------------------------------------------------
程序功能: 使用opencv打开USB摄像头,在实时显示的图像中,点击鼠标的任意两个位置,显示出裁剪区域图像(按下键盘的r键,重置裁剪区域)
---------------------------------------------------------------
"""
import cv2
# ==================== 全局变量 ====================
# 存储鼠标点击的两个点坐标
points = []
# 存储裁剪后的图像(保留备用,虽然当前未大量使用)
cropped = None
# 裁剪窗口名称常量
CROP_WINDOW_NAME = 'Cropped Region'
# ==================== 安全销毁窗口函数 ====================
def safe_destroy_window(window_name):
"""
安全销毁OpenCV窗口(如果窗口存在则销毁,不存在则忽略错误)
参数:
window_name: 要销毁的窗口名称
"""
try:
# 检查窗口是否存在(getWindowProperty返回-1表示窗口不存在)
if cv2.getWindowProperty(window_name, cv2.WND_PROP_VISIBLE) >= 0:
cv2.destroyWindow(window_name)
except cv2.error:
# 如果窗口不存在,忽略错误
pass
# ==================== 鼠标回调函数 ====================
def mouse_callback(event, x, y, flags, param):
"""
鼠标事件回调函数
参数:
event: 鼠标事件类型(如左键按下、右键按下、移动等)
x, y: 鼠标在窗口中的坐标(像素)
flags: 事件标志(如Ctrl、Shift等按键状态)
param: 用户传递的额外参数
"""
global points # 声明使用全局变量 points
# 检测鼠标左键按下事件
if event == cv2.EVENT_LBUTTONDOWN:
# 将点击坐标添加到 points 列表
points.append((x, y))
# 如果 points 中存储的点超过2个
if len(points) > 2:
# 只保留最近的两个点(即最后两个)
# 这样每次点击新点,会自动丢弃最早的点
points = points[-2:]
# ==================== 初始化摄像头 ====================
# 打开默认摄像头(设备索引通常是 0)
cap = cv2.VideoCapture(0)
# 检查摄像头是否成功打开
if not cap.isOpened():
print("错误:无法打开摄像头")
exit()
# ==================== 创建窗口并绑定鼠标回调 ====================
# 创建名为 'Camera Feed' 的窗口
window_name = 'Camera Feed'
cv2.namedWindow(window_name)
# 将鼠标回调函数绑定到窗口
# 当在 'Camera Feed' 窗口中进行鼠标操作时,会自动调用 mouse_callback
cv2.setMouseCallback(window_name, mouse_callback)
# ==================== 程序使用提示 ====================
print("左键点击两个点以选择矩形区域")
print("按 'r' 重置选区,按 'q' 退出")
# ==================== 主循环:实时采集并处理 ====================
while True:
# 从摄像头读取一帧图像
ret, frame = cap.read()
# 检查是否成功读取到图像
if not ret:
print("错误:无法获取帧")
break
# 创建原始图像的副本用于显示(避免在原图上直接修改)
display_frame = frame.copy()
# ==================== 处理裁剪区域 ====================
# 如果已经选择了两个点(形成矩形区域)
if len(points) == 2:
# 获取两个点的坐标
x1, y1 = points[0] # 第一个点的 (x, y)
x2, y2 = points[1] # 第二个点的 (x, y)
# 确定矩形的左上角和右下角坐标
# 因为用户可能从右下往左上拖拽,需要取最小/最大值
x_min, x_max = min(x1, x2), max(x1, x2) # 左边界和右边界
y_min, y_max = min(y1, y2), max(y1, y2) # 上边界和下边界
# 在显示图像上绘制选区矩形框(绿色,线宽2像素)
# 这样可以直观地看到裁剪区域的位置
cv2.rectangle(display_frame, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
# 检查矩形是否有效(宽度和高度都大于0)
if x_max > x_min and y_max > y_min:
# 从原始图像中裁剪出选中区域
# 注意:使用 frame(原图)而不是 display_frame(带框的副本)
cropped = frame[y_min:y_max, x_min:x_max]
# 在新窗口中显示裁剪后的图像
cv2.imshow(CROP_WINDOW_NAME, cropped)
else:
# 如果矩形无效(宽度或高度为0),则安全关闭裁剪窗口
safe_destroy_window(CROP_WINDOW_NAME)
else:
# 如果未选择两个点(0个或1个点),安全关闭裁剪窗口
safe_destroy_window(CROP_WINDOW_NAME)
# ==================== 显示主画面 ====================
# 显示带有矩形框(如果有)的摄像头画面
cv2.imshow(window_name, display_frame)
# ==================== 键盘控制 ====================
key = cv2.waitKey(1) & 0xFF # 获取按键(等待1毫秒)
if key == ord('q'): # 按 'q' 键退出程序
break
elif key == ord('r'): # 按 'r' 键重置选区
points = [] # 清空点的列表,清除选区
safe_destroy_window(CROP_WINDOW_NAME) # 安全关闭裁剪窗口
# ==================== 资源释放 ====================
cap.release() # 释放摄像头设备
cv2.destroyAllWindows() # 关闭所有OpenCV创建的窗口
操作手順
- ターミナルを開き、Python プログラムのディレクトリに移動してプログラムを実行します。以下のコマンドを入力してください。
python 13_opencv_cut_img_mouse.py
実験結果
USB カメラを開き、マウスで任意の 2 点をクリックして矩形のクロップ領域を選択すると、クロップ結果がリアルタイムで表示されます。選択範囲のリセットにも対応しています。
参考結果:
お問い合わせ
資料のダウンロード・技術サポートについては、HumansX株式会社までお問い合わせください。
ドキュメント