2022-06-14 OpenCV Python 工具类

工具类

import math

import cv2 as cv
import numpy as np

from shapely.geometry import Point, Polygon

def log(*args):
    print(args)


# 显示图像
def show(title, image):
    cv.namedWindow(title, cv.WINDOW_NORMAL)
    cv.imshow(zh_ch(title), image)
    pass

# 解决中文乱码问题
def zh_ch(string):
    return string.encode("gbk").decode(errors="ignore")

# 图像缩放
def resize(img, fx):
    return cv.resize(img, None, fx=fx, fy=fx)

# 图像平移
def move(src, x, y):
    # 构建平移矩阵
    M = np.float32([[1, 0, x], [0, 1, y]])
    # 应用平移矩阵
    move = cv.warpAffine(src, M, (src.shape[1], src.shape[0]))
    return move
    pass


# 旋转图像全部
# opencv的旋转会保持图片大小不变,旋转后空白地方补黑,多的地方丢失.所以这里写一个无损旋转函数
def rotationAll(src, angle):
    # 拿到原图的宽高中心点
    h, w = src.shape[:2]
    cX = w / 2
    cY = h / 2

    # 拿到旋转矩阵,默认是逆时针,我们习惯顺时针,所以这里角度取反
    M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
    # 默认旋转后图像保持原图大小,那么转出去的部分就会丢失,我们这里保留图像所有内容,那么图像就会变大
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    # 计算新图像的大小
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    rotated_image = cv.warpAffine(src, M, (nW, nH))

    return rotated_image
    pass


# 旋转图像像素点
# 结合rotationAll()函数使用,将旋转前的像素映射到旋转后的图像中
def rotationAllPoint(src, points, angle):
    # 拿到原图的宽高中心点
    h, w = src.shape[:2]
    cX = w / 2
    cY = h / 2

    # 拿到旋转矩阵,默认是逆时针,我们习惯顺时针,所以这里角度取反
    M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
    # 默认旋转后图像保持原图大小,那么转出去的部分就会丢失,我们这里保留图像所有内容,那么图像就会变大
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    # 计算新图像的大小
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # 要映射的点
    pts = np.float32(points).reshape([-1, 2])
    pts = np.hstack([pts, np.ones([len(pts), 1])]).T
    target_point = np.dot(M, pts)
    target_point = [[target_point[0][x], target_point[1][x]] for x in range(len(target_point[0]))]
    return target_point

    pass


# 旋转图像中的点还原到原图坐标
# 结合rotationAll()函数使用,将旋转后图像中的点映射到旋转前图像中
def restorePoint(point, rotate, src, angle):
    centerSrc = (src.shape[1] / 2, src.shape[0] / 2)
    centerRotate = (rotate.shape[1] / 2, rotate.shape[0] / 2)
    # 旋转后图像和原图大小不一样,先计算差值
    difference = (point[0] - (centerRotate[0] - centerSrc[0]), point[1] - (centerRotate[1] - centerSrc[1]))
    result = rotatePoint(centerSrc, difference, -angle)
    return result
    pass


# 一个点绕中心点旋转一定角度后的坐标
def rotatePoint(center, rotater, angle):
    # 角度转弧度
    radian = angle * math.pi / 180
    # 三角函数计算坐标
    x = (rotater[0] - center[0]) * math.cos(radian) - (rotater[1] - center[1]) * math.sin(radian) + center[0]
    y = (rotater[0] - center[0]) * math.sin(radian) + (rotater[1] - center[1]) * math.cos(radian) + center[1]
    return (x, y)
    pass


# 绘制点
def drawPoint(canvas, p):
    try:
        cv.circle(canvas, (round(p[0]), round(p[1])), 1, (0, 0, 255), 3)
    except Exception:
        log(p)
        log("绘制点异常")

    pass


# 绘制线
def drawLine(canvas, p1, p2):
    cv.line(canvas, (round(p1[0]), round(p1[1])), (round(p2[0]), round(p2[1])), (0, 0, 255), 2)
    pass


# 绘制矩形
def drawRectangle(canvas, p1, p2):
    cv.rectangle(canvas, (round(p1[0]), round(p1[1])), (round(p2[0]), round(p2[1])), (0, 0, 255), 2)
    pass


# 绘制矩形
def drawRectangle2(canvas, p1, w, h):
    cv.rectangle(canvas, (round(p1[0]), round(p1[1])), (round(p1[0] + w), round(p1[1] + h)), (0, 0, 255), 2)
    pass


# 绘制多边形,多个点连起来
def drawPolylines(canvas, points):
    # 坐标数据取整
    points_temp = []
    for point in points:
        points_temp.append([round(point[0]), round(point[1])])
        pass
    # 坐标数组转点集np.arry[]
    pts = np.array(points_temp)
    cv.polylines(canvas, [pts], True, (0, 0, 255), 2)
    pass


# 绘制文本
def drawText(canvas, text, p):
    font = cv.FONT_HERSHEY_SIMPLEX
    cv.putText(canvas, text, (round(p[0]), round(p[1])), font, 2, (0, 0, 255), 2, cv.LINE_AA)
    pass


# 获取两点间距离
def getDistance(p1, p2):
    distance = math.pow((p1[0] - p2[0]), 2) + math.pow((p1[1] - p2[1]), 2)
    distance = math.sqrt(distance)
    return distance


# 已知三个角和一条边,求另2条边
def calSide(angles, a):
    angleA = angles[0]
    angleB = angles[1]
    angleC = angles[2]

    b = math.sin(angleB / 180 * math.pi) * a
    c = math.cos(angleB / 180 * math.pi) * a
    return b, c


# 计算线段中点1到点2的方向
def calAngleLine(p1, p2):
    angle = 0
    x1, y1 = p1
    x2, y2 = p2

    # 水平
    if y1 == y2:
        # 右
        if x1 < x2:
            angle = 0
        # 左
        elif x1 > x2:
            angle = 180
        # 同一个点
        else:
            angle = 0
    # 向上
    elif y1 > y2:
        # 右上
        if x1 < x2:
            angle = 360 - calAngle(p1, p2, (x2, y1))[0]
        # 左上
        elif x1 > x2:
            angle = 180 + calAngle(p1, p2, (x2, y1))[0]
        # 上
        else:
            angle = 270
    # 向下
    else:
        # 右下
        if x1 < x2:
            angle = calAngle(p1, p2, (x2, y1))[0]
        # 左下
        elif x1 > x2:
            angle = 180 - calAngle(p1, p2, (x2, y1))[0]
        # 下
        else:
            angle = 90
    return angle


# 计算三个点绘制三角形的角度,返回值是个数组,里面的角度对应传递3个点的顺序
def calAngle(p1, p2, p3):
    angles = []
    a = math.sqrt((p2[0] - p3[0]) * (p2[0] - p3[0]) + (p2[1] - p3[1]) * (p2[1] - p3[1]))
    b = math.sqrt((p1[0] - p3[0]) * (p1[0] - p3[0]) + (p1[1] - p3[1]) * (p1[1] - p3[1]))
    c = math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]))
    A = math.degrees(math.acos((a * a - b * b - c * c) / (-2 * b * c)))
    B = math.degrees(math.acos((b * b - a * a - c * c) / (-2 * a * c)))
    C = math.degrees(math.acos((c * c - a * a - b * b) / (-2 * a * b)))
    angles.append(A)
    angles.append(B)
    angles.append(C)
    return angles


# 计算2个角度之间的差
def angleDifference(angle1, angle2):
    return 180 - abs(abs(angle1 - angle2) - 180)
    pass


# 角度校正,360=0,361=1
def rectifyAngle(angle):
    # u.log(angle)
    if angle >= 360:
        angle = angle - 360
    elif angle < 0:
        angle = angle + 360

    if (angle < 0) | (angle >= 360):
        return rectifyAngle(angle)

    return angle


# 计算一个点在一定角度上多远距离的点坐标
def calPoint4AngleDistance(center, angle, distance):
    angle = rectifyAngle(angle)
    x, y = center
    point = ()
    if angle >= 360:
        angle %= 360
    # 右
    if angle == 0:
        point = (x + distance, y)
        pass
    # 下
    elif angle == 90:
        point = (x, y + distance)
        pass
    # 左
    elif angle == 180:
        point = (x - distance, y)
        pass
    # 上
    elif angle == 270:
        point = (x, y - distance)
        pass
    # 右下
    elif angle > 0 and angle < 90:
        angles = []
        angles.append(90)
        angles.append(angle)
        angles.append(90 - angle)
        b, c = calSide(angles, distance)
        point = (x + c, y + b)
        pass
    # 左下
    elif angle > 90 and angle < 180:
        angles = []
        angles.append(90)
        angles.append(180 - angle)
        angles.append(angle - 90)
        b, c = calSide(angles, distance)
        point = (x - c, y + b)
        pass
    # 左上
    elif angle > 180 and angle < 270:
        angles = []
        angles.append(90)
        angles.append(angle - 180)
        angles.append(270 - angle)
        b, c = calSide(angles, distance)
        point = (x - c, y - b)
        pass
    # 右上
    elif angle > 270 and angle < 360:
        angles = []
        angles.append(90)
        angles.append(360 - angle)
        angles.append(angle - 270)
        b, c = calSide(angles, distance)
        point = (x + c, y - b)
        pass

    return point


# 获取图像中白色像素点数量
def getWhiteCount(src):
    count = 0
    w, h = src.shape
    for j in range(w):
        for k in range(h):
            if src[j, k] == (255.0):
                count += 1

    return count
    pass


# 获取白色像素点坐标集
def getWhiteCount(src):
    points = []
    w, h = src.shape
    for j in range(w):
        for k in range(h):
            if src[j, k] == (255.0):
                points.append([j, k])

    return points
    pass


# 提取图像中所有白色像素点的坐标
def getWhitePoints(src):
    whites = []
    w, h = src.shape
    for j in range(w):
        for k in range(h):
            if src[j, k] == (255.0):
                whites.append([k, j])

    return whites

    pass


# 角度校正
def rectifyAngle(angle):
    # print(angle)
    if angle >= 360:
        angle = angle - 360
    elif angle < 0:
        angle = angle + 360

    if (angle < 0) | (angle >= 360):
        return rectifyAngle(angle)

    return angle


# 判断2个矩形有没有重合点
def rectOverlay(rect1, rect2):
    lt1, rt1, lb1, rb1 = rect1
    lt2, rt2, lb2, rb2 = rect2
    x1 = lt1[0]
    y1 = lt1[1]
    w1 = rt1[0] - x1
    h1 = lb1[1] - y1
    x2 = lt2[0]
    y2 = lt2[1]
    w2 = rt2[0] - x2
    h2 = lb2[1] - y2
    if x1 > x2 + w2 or x2 > x1 + w1:
        return False
    if y1 > y2 + h2 or y2 > y1 + h1:
        return False
    return True
    pass


# 判断一个点在不在一个多边形内
def pointInPolylines(point, points):
    # 定义多边形的顶点
    polygon = Polygon(points)
    # 定义要判断的点
    point = Point(point)
    # 判断点是否在多边形内
    inside = polygon.contains(point)
    return inside
    pass
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容