HumansXドキュメントセンター 公式サイトへ ↗

2.14 さまざまな角度での画像の回転

実験の目的

  1. 画像を取得し、さまざまな角度で回転させた画像を表示します。

  2. 回転変換を応用できるようになります。

機能要件

さまざまな角度で画像を回転させ、結果を表示します。

ハードウェアの準備

No. 名称 数量 備考
1 RDK X5 1 組み込みメインボード(32GB メモリーカード付き)。上位機(PC 側)システムとして動作します。
2 カードリーダー 1 システムイメージの書き込みに使用します。
3 USB カメラ 1 画像を取得します。
4 電源ケーブル 1 電源供給用です。
5 LAN ケーブル 1 ネットワーク接続用です。

回路接続

ソフトウェア設計

設計フローチャート

ソースコードのダウンロード

ソースコードファイル:14_opencv_rotate_img.rar

プログラムコード

完全なプロジェクトコードは(ソースコードファイル)をクリックしてダウンロードしてください。

"""
---------------------------------------------------------------
程序功能: 使用opencv打开USB摄像头,在实时显示的图像中,按照30,60,90,120度旋转图像

---------------------------------------------------------------
"""

import cv2
import numpy as np
import math

# ==================== 辅助函数定义 ====================
def rotate_bound(image, angle):
    """
    完整旋转图像(不裁剪),返回包含整个旋转后图像的新图像

    普通旋转会裁剪掉超出边界的部分,这个函数会计算新图像的尺寸,
    确保旋转后的完整图像都在画布内。

    参数:
        image: 输入图像(numpy数组)
        angle: 旋转角度(度数,正值表示逆时针旋转)

    返回:
        旋转后的完整图像(尺寸会自动调整,不会裁剪)
    """
    # 获取原始图像的尺寸
    (h, w) = image.shape[:2]
    # 计算图像中心点坐标(宽度的一半,高度的一半)
    (cX, cY) = (w // 2, h // 2)

    # 获取旋转矩阵
    # cv2.getRotationMatrix2D(center, angle, scale)
    #   center: 旋转中心点
    #   angle: 旋转角度(正值 = 逆时针)
    #   scale: 缩放因子(1.0 表示不缩放)
    # 注意:传入 -angle 是为了让正角度表示逆时针旋转
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)

    # ========== 计算旋转后图像的新边界尺寸 ==========
    # 从旋转矩阵中提取 cos 和 sin 的绝对值
    # M[0,0] = cosθ, M[0,1] = sinθ
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # 计算旋转后的新宽度和新高度
    # 公式: new_w = h * |sinθ| + w * |cosθ|
    #      new_h = h * |cosθ| + w * |sinθ|
    new_w = int((h * sin) + (w * cos))
    new_h = int((h * cos) + (w * sin))

    # ========== 调整旋转矩阵的平移部分,使图像居中 ==========
    # 原来旋转矩阵是以原图像中心为中心旋转
    # 现在需要将旋转后的图像平移到新画布的中心位置
    M[0, 2] += (new_w / 2) - cX  # 调整 X 方向平移量
    M[1, 2] += (new_h / 2) - cY  # 调整 Y 方向平移量

    # 执行仿射变换(旋转)
    # cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)
    #   src: 源图像
    #   M: 变换矩阵
    #   dsize: 输出图像尺寸 (new_w, new_h)
    #   flags: 插值方法(INTER_LINEAR = 线性插值)
    #   borderMode: 边界填充模式(BORDER_CONSTANT = 常数填充)
    #   borderValue: 填充颜色((0,0,0) = 黑色)
    rotated = cv2.warpAffine(image, M, (new_w, new_h), 
                             flags=cv2.INTER_LINEAR, 
                             borderMode=cv2.BORDER_CONSTANT, 
                             borderValue=(0, 0, 0))
    return rotated

def resize_half(img):
    """
    将图像缩小为原来的一半(宽高各 ÷ 2)

    使用 INTER_AREA 插值方法,适合图像缩小,能减少锯齿和波纹

    参数:
        img: 输入图像

    返回:
        缩小为一半尺寸的图像
    """
    h, w = img.shape[:2]
    # cv2.resize(src, dsize, interpolation)
    #   dsize: 目标尺寸 (width, height)
    #   INTER_AREA: 区域插值,适合图像缩小
    return cv2.resize(img, (w // 2, h // 2), interpolation=cv2.INTER_AREA)

# ==================== 初始化摄像头 ====================
# 打开默认摄像头(设备索引通常是 0)
cap = cv2.VideoCapture(0)

# 检查摄像头是否成功打开
if not cap.isOpened():
    print("错误:无法打开摄像头")
    exit()

print("按 'q' 键退出")

# ==================== 主循环:实时采集并旋转 ====================
while True:
    # 从摄像头读取一帧图像
    ret, frame = cap.read()

    # 检查是否成功读取到图像
    if not ret:
        print("错误:无法获取帧")
        break

    # ==================== 生成不同角度的旋转图像 ====================
    # 对每一帧图像分别旋转 30°、60°、90°、180°
    # 先完整旋转(不裁剪),再缩小为原来的一半(便于拼接显示)
    img30 = resize_half(rotate_bound(frame, 30))   # 旋转30度后缩小
    img60 = resize_half(rotate_bound(frame, 60))   # 旋转60度后缩小
    img90 = resize_half(rotate_bound(frame, 90))   # 旋转90度后缩小
    img180 = resize_half(rotate_bound(frame, 180)) # 旋转180度后缩小

    # ==================== 统一所有图片的尺寸 ====================
    # 由于旋转角度不同,旋转后的图像尺寸可能略有差异
    # 以 img30 的尺寸为基准,将其它图片缩放至相同尺寸
    target_h, target_w = img30.shape[:2]  # 获取基准尺寸
    img60 = cv2.resize(img60, (target_w, target_h))
    img90 = cv2.resize(img90, (target_w, target_h))
    img180 = cv2.resize(img180, (target_w, target_h))

    # ==================== 拼接图像(2x2网格) ====================
    # 水平拼接第一行:30° 和 60° 并排
    # np.hstack() 将多个数组水平堆叠(左右拼接)
    top_row = np.hstack((img30, img60))

    # 水平拼接第二行:90° 和 180° 并排
    bottom_row = np.hstack((img90, img180))

    # 垂直拼接两行:上下堆叠,形成2x2网格
    # np.vstack() 将多个数组垂直堆叠(上下拼接)
    combined = np.vstack((top_row, bottom_row))

    # ==================== 显示结果 ====================
    # 显示原始图像
    cv2.imshow("raw_img", frame)
    # 显示2x2网格的旋转效果图
    cv2.imshow('Full Rotated Views (30/60/90/180)', combined)

    # ==================== 键盘控制 ====================
    # 等待1毫秒,检测键盘输入
    # 如果按下 'q' 键,则退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# ==================== 资源释放 ====================
cap.release()          # 释放摄像头设备
cv2.destroyAllWindows()  # 关闭所有OpenCV创建的窗口

操作手順

  1. ターミナルを開き、Python プログラムのディレクトリに移動してプログラムを実行します。以下のコマンドを入力してください。
python 14_opencv_rotate_img.py

実験結果

USB カメラを開き、リアルタイム映像をそれぞれ 30°、60°、90°、180° 回転させ、2×2 のグリッドで比較表示します。

参考結果:

お問い合わせ

資料のダウンロード・技術サポートについては、HumansX株式会社までお問い合わせください。