首页 > 其他分享 >c~视觉~CV~合集1

c~视觉~CV~合集1

时间:2024-09-03 17:29:20浏览次数:12  
标签:img image cv2 编辑 np 视觉 合集 CV 255


 哈哈 准备开始挪一些 cv相的合集~ 

一、CVの文档自动扫描仪

 介绍如何使用 OpenCV + GrabCut实现一个文档自动扫描仪。

背景介绍

    文档扫描是将物理文档转换为数字形式的过程。可以通过扫描仪或手机摄像头拍摄图像来完成。我们将在本文中讨论如何使用计算机视觉和图像处理技术有效地实现这一目标。

    有许多软件解决方案和应用程序可以做到这一点。借助计算机视觉的力量,从物理文档到扫描文档的过程与将相机对准文档并单击图片没有太大区别。速度和易用性是此类解决方案的主要优势,它们可用于计算机和移动设备。

    让我们看看如何使用经典的计算机视觉技术创建一个简单的 OpenCV 文档扫描仪,其中输入将是我们要扫描的文档的图像,而预期的输出将是正确对齐的文档扫描图像。

实现目标

    如下图所示,给定一张包含文档的图片,通过代码自动将文档提取并矫正。

c~视觉~CV~合集1_视觉

编辑

实现步骤

    测试原图如下:

c~视觉~CV~合集1_视觉_02

编辑

实现步骤:

【1】通过形态学处理,得到一个空白页。这里直接用闭运算即可,闭运算是膨胀,然后是腐蚀。不断重复这些关闭操作,直到你得到一个空白页。 

c~视觉~CV~合集1_视觉_03

编辑

kernel = np.ones((5,5),np.uint8)
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations= 3)

c~视觉~CV~合集1_视觉_04

编辑

为什么我们想要一个空白文档呢?因为后面会进行边缘检测,并且我们不希望被页面的文字内容干扰该。

【2】用GrabCut去掉背景。

  • 它只需要在前景中的对象周围设置一个边界框,边界框之外的所有内容都被视为背景。  
  • GrabCut 会自动消除所有背景,即使在边界框内也是如此。现在剩下的就是前景对象。 

我们将角落 20 像素作为背景,GrabCut 会自动确定前景和背景,只留下文档。

mask = np.zeros(img.shape[:2],np.uint8)
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
rect = (20,20,img.shape[1]-20,img.shape[0]-20)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]

c~视觉~CV~合集1_视觉_05

编辑

【3】Canny边缘检测 + 轮廓提取。

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11, 11), 0)
# Edge Detection.
canny = cv2.Canny(gray, 0, 200)
canny = cv2.dilate(canny, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
  • 首先将空白页的图像转换为灰度,因为canny只对灰度图像起作用。
  • 然后执行高斯模糊以去除图像中的噪声。 
  • 最后,对图像进行精确边缘检测。 
  • 此外,放大图像以获得文档的细轮廓。
# Blank canvas.
con = np.zeros_like(img)
# Finding contours for the detected edges.
contours, hierarchy = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Keeping only the largest detected contour.
page = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
con = cv2.drawContours(con, page, -1, (0, 255, 255), 3)
  • 根据大小对检测到的轮廓进行排序
  • 只保留检测到的最大轮廓 
  • 然后在空白画布上绘制这个检测到的最大轮廓

c~视觉~CV~合集1_视觉_06

编辑

【4】角点检测 + 排序。

# Blank canvas.
con = np.zeros_like(img)
# Loop over the contours.
for c in page:
  # Approximate the contour.
  epsilon = 0.02 * cv2.arcLength(c, True)
  corners = cv2.approxPolyDP(c, epsilon, True)
  # If our approximated contour has four points
  if len(corners) == 4:
      break
cv2.drawContours(con, c, -1, (0, 255, 255), 3)
cv2.drawContours(con, corners, -1, (0, 255, 0), 10)
# Sorting the corners and converting them to desired shape.
corners = sorted(np.concatenate(corners).tolist())

# Displaying the corners.
for index, c in enumerate(corners):
  character = chr(65 + index)
  cv2.putText(con, character, tuple(c), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1, cv2.LINE_AA)

c~视觉~CV~合集1_视觉_07

编辑

角点排序:

def order_points(pts):
    '''Rearrange coordinates to order:
      top-left, top-right, bottom-right, bottom-left'''
    rect = np.zeros((4, 2), dtype='float32')
    pts = np.array(pts)
    s = pts.sum(axis=1)
    # Top-left point will have the smallest sum.
    rect[0] = pts[np.argmin(s)]
    # Bottom-right point will have the largest sum.
    rect[2] = pts[np.argmax(s)]

    diff = np.diff(pts, axis=1)
    # Top-right point will have the smallest difference.
    rect[1] = pts[np.argmin(diff)]
    # Bottom-left will have the largest difference.
    rect[3] = pts[np.argmax(diff)]
    # Return the ordered coordinates.
    return rect.astype('int').tolist()

确定目标坐标:一旦获得文档的角点,接下来只需要目标坐标来执行透视变换和对齐文档。

【5】透视变换对齐文档。

# Getting the homography.
M = cv2.getPerspectiveTransform(np.float32(corners), np.float32(destination_corners))
# Perspective transform using homography.
final = cv2.warpPerspective(orig_img, M, (destination_corners[2][0], destination_corners[2][1]), flags=cv2.INTER_LINEAR)

c~视觉~CV~合集1_视觉_08

编辑

【6】扩展测试。

    我们在 23 种不同的背景和不同的方向上进行了测试,自动文档扫描仪几乎在所有情况下都运行良好。

c~视觉~CV~合集1_视觉_09

编辑

失败情况:

c~视觉~CV~合集1_视觉_10

编辑

当文档的一部分在图像之外时,可能会丢失一个角落,GrabCut 无法扫描。这是使用 GrabCut 的唯一限制。在大多数其他情况下,我们的文档扫描仪运行良好。

    这种方法的另一个限制是边缘和轮廓检测。如果背景中存在大量噪声,则会检测到许多不需要的边缘,并且在某些情况下,轮廓检测步骤可能会将这些边缘误认为是文档。此外,如果文档边缘与背景无法区分,则轮廓检测可能无法完全正常工作。

    但 GrabCut 和轮廓检测并不是唯一经过验证的文档扫描方法。对于消费级文档扫描解决方案,首选角点检测和分割等深度学习技术,因为它们更强大。

参考链接:

https://learnopencv.com/automatic-document-scanner-using-opencv/

二、CVの复杂背景下的直线提取

 介绍一个基于OpenCV实现的复杂背景下直线提取实例 

案例来源于网络,如下图所示,要求提取图中的直线轮廓并标出:

c~视觉~CV~合集1_视觉_11

编辑

实现步骤与代码

    【1】中值滤波滤除噪点(中值滤波对椒盐噪声效果较好)。

img = cv2.imread('test.png')
cv2.imshow('src', img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

blur = cv2.medianBlur(gray, 3)
cv2.imshow('blur',blur)

c~视觉~CV~合集1_视觉_12

编辑

  【2】滤波图像取反,然后使用HoughLinesP(累计概率霍夫变换)检测直线。图像取反原因是HoughLinesP是在黑色背景中找白色直线,这样效果更好。

blur = cv2.bitwise_not(blur)
cv2.imshow('bitwise_not',blur)
cv2.waitKey(0)

temp = np.zeros(blur.shape, np.uint8)
# Detect and draw lines
lines = cv2.HoughLinesP(blur, 1, np.pi/180, 10, minLineLength=50, maxLineGap=30)

for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(temp, (x1, y1), (x2, y2), (255, 255, 255), 2)

c~视觉~CV~合集1_视觉_13

编辑

c~视觉~CV~合集1_视觉_14

编辑

【3】将检测到的直线的二值图细化。

cv2.imshow('temp', temp)
temp[temp==255] = 1
skeleton = morphology.skeletonize(temp)
thin = skeleton.astype(np.uint8)*255
cv2.imshow("thin",thin)

c~视觉~CV~合集1_视觉_15

编辑

  【4】使用细化图像再做一次HoughLinesP(累计概率霍夫变换)检测直线。

# Detect and draw lines again
lines = cv2.HoughLinesP(thin, 1, np.pi/180, 20, minLineLength=50, maxLineGap=30)
print(len(lines))  
 

for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

c~视觉~CV~合集1_视觉_16

编辑

三、CVの测量圆弧长度

 介绍基于OpenCV实现两种方法测量圆弧长度

c~视觉~CV~合集1_视觉_17

编辑

 要求:如上所示,分别用OpenCV计算出图1和图2中圆弧的长度。因为OpenCV中没有提供现成计算圆弧的方法,所以需要自己编写,本文将提供2种不同的方法来实现,仅供参考。

实现步骤

c~视觉~CV~合集1_视觉_18

编辑

  首先以图1为例,如上图所示,方法一具体实现步骤如下:

  【1】二值化 + 查找轮廓

img = cv2.imread('11.png')
cv2.imshow('src',img)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray, 70, 255, cv2.THRESH_BINARY)

contours,hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

  【2】查找轮廓凸包缺陷,确定圆弧起点和终点坐标

hull = cv2.convexHull(contours[0],returnPoints=False)#默认returnPoints=True

defects = cv2.convexityDefects(contours[0],hull)
start = end = (0,0)
for i in range(0,defects.shape[0]):
  s,e,f,d = defects[i,0]
  start = tuple(contours[0][s][0])
  end = tuple(contours[0][e][0])
  far = tuple(contours[0][f][0])
  if d > 5000:
    cv2.line(img,start,end,[0,255,0],2)#凸包
    #cv2.circle(img,far,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,end,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,start,5,[0,0,255],-1)#凸包缺陷点
    break
cv2.imshow('defects', img)
cv2.waitKey(0)

c~视觉~CV~合集1_视觉_19

编辑

【3】获取轮廓最小外接圆,获取圆心,计算圆弧角度

center,radius = cv2.minEnclosingCircle(contours[0])
cv2.circle(img,(int(center[0]),int(center[1])),8,(255,0,255),-1)
cv2.circle(img,end,8,[0,255,255],-1)#凸包缺陷点
cv2.circle(img,start,8,[0,255,255],-1)#凸包缺陷点
cv2.line(img,start,(int(center[0]),int(center[1])),[0,255,0],2)#凸包
cv2.line(img,end,(int(center[0]),int(center[1])),[0,255,0],2)#凸包

angle = cal_ang(start,center,end)
print('angle = %0.2f' % angle)

c~视觉~CV~合集1_视觉_20

编辑

c~视觉~CV~合集1_视觉_21

编辑

【4】通过外接圆周长角度比例来计算弧长

length = (1 - angle / 360.0) * math.pi * radius * 2
print((angle / 360.0))
print('radius = %0.2f' % radius)
strL = 'length=%0.2f' % length

cv2.putText(img,strL,(int(center[0]-40),int(center[1]+40)),0,0.8,(255,0,0),2) 
cv2.imshow('result', img)

angle_1 = cal_ang(start, center, ((center[0]+100),(center[1])))
angle_2 = cal_ang(end, center, ((center[0]+100),(center[1])))
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,-angle_1,0,(255,0,255),2, cv2.LINE_AA)
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,0,angle_2,(255,0,255),2, cv2.LINE_AA)

cv2.imshow('result', img)
cv2.imwrite('result.bmp',img)

cv2.waitKey(0)
cv2.destroyAllWindows()

c~视觉~CV~合集1_视觉_22

编辑

    以图2做测试,验证结果:

c~视觉~CV~合集1_视觉_23

编辑

方法二将步骤【2】替换为通过角点检测来获取弧线端点坐标:

feature_params = dict(maxCorners = 2,
                      qualityLevel = 0.3,
                      minDistance = 50,
                      blockSize = 5 )

corners = cv2.goodFeaturesToTrack(thresh,mask=None,**feature_params)

print ('cornerNum = ' + str(len(corners)))

for i in range(0,len(corners)):
    cv2.circle(img,(int(corners[i][0][0]),int(corners[i][0][1])),8,(0,255,0),-1, cv2.LINE_AA)
cv2.imshow('cornerNum', img)

c~视觉~CV~合集1_视觉_24

编辑

最终结果:

c~视觉~CV~合集1_视觉_25

编辑

  测试图2结果:

c~视觉~CV~合集1_视觉_26

编辑

四、CVの魔方颜色识别与色块排序

     为了做自动魔方识别与复原项目,需要用图像处理的方法识别魔方每个色块的位置与颜色。相机拍摄的魔方单面图像如下:

c~视觉~CV~合集1_视觉_27

编辑

实现步骤

    本文主要使用OpenCV来实现魔方颜色识别与色块位置排序。

    【1】颜色识别。设定每个色块在HSV颜色空间的范围来判断和提取颜色。

image = cv2.imread('1.png')
original = image.copy()
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = np.zeros(image.shape, dtype=np.uint8)

colors = {
    'gray': ([76, 0, 41], [179, 255, 70]),        # Gray
    'blue': ([69, 120, 100], [179, 255, 255]),    # Blue
    'yellow': ([21, 110, 117], [45, 255, 255]),   # Yellow
    'orange': ([0, 110, 125], [17, 255, 255])     # Orange
    }

    【2】提取色块掩码。在步骤【1】的基础上添加形态学处理,然后通过或操作

(cv2.bitwise_or)

将所有色块区域提取出来。

# Color threshold to find the squares
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
for color, (lower, upper) in colors.items():
    lower = np.array(lower, dtype=np.uint8)
    upper = np.array(upper, dtype=np.uint8)
    color_mask = cv2.inRange(image, lower, upper)
    color_mask = cv2.morphologyEx(color_mask, cv2.MORPH_OPEN, open_kernel, iterations=1)
    color_mask = cv2.morphologyEx(color_mask, cv2.MORPH_CLOSE, close_kernel, iterations=5)

    color_mask = cv2.merge([color_mask, color_mask, color_mask])
    mask = cv2.bitwise_or(mask, color_mask)

c~视觉~CV~合集1_视觉_28

编辑

【3】色块排序。排序使用imutils包的contours模块实现。

from imutils import contours
先做一次从上到下排序,再做一次从左到右排序即可:
gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
cnts = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# Sort all contours from top-to-bottom or bottom-to-top
(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")

# Take each row of 3 and sort from left-to-right or right-to-left
cube_rows = []
row = []
for (i, c) in enumerate(cnts, 1):
    row.append(c)
    if i % 3 == 0:  
        (cnts, _) = contours.sort_contours(row, method="left-to-right")
        cube_rows.append(cnts)
        row = []

# Draw text
number = 0
for row in cube_rows:
    for c in row:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(original, (x, y), (x + w, y + h), (36,255,12), 2)

        cv2.putText(original, "#{}".format(number + 1), (x,y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,255), 2)
        number += 1

c~视觉~CV~合集1_视觉_29

编辑

c~视觉~CV~合集1_视觉_30

编辑

当然,还可以从下到上,从右向左排序。只需要设置下面的method即可:

(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")
(cnts, _) = contours.sort_contours(row, method="left-to-right")

c~视觉~CV~合集1_视觉_31

编辑

c~视觉~CV~合集1_视觉_32

编辑

c~视觉~CV~合集1_视觉_33

编辑

  【4】如何获取HSV范围。可以使用下面代码,通过滑动条动态调整的方法获取:

import cv2
import numpy as np

def nothing(x):
    pass

# Load image
image = cv2.imread('1.jpg')

# Create a window
cv2.namedWindow('image')

# Create trackbars for color change
# Hue is from 0-179 for Opencv
cv2.createTrackbar('HMin', 'image', 0, 179, nothing)
cv2.createTrackbar('SMin', 'image', 0, 255, nothing)
cv2.createTrackbar('VMin', 'image', 0, 255, nothing)
cv2.createTrackbar('HMax', 'image', 0, 179, nothing)
cv2.createTrackbar('SMax', 'image', 0, 255, nothing)
cv2.createTrackbar('VMax', 'image', 0, 255, nothing)

# Set default value for Max HSV trackbars
cv2.setTrackbarPos('HMax', 'image', 179)
cv2.setTrackbarPos('SMax', 'image', 255)
cv2.setTrackbarPos('VMax', 'image', 255)

# Initialize HSV min/max values
hMin = sMin = vMin = hMax = sMax = vMax = 0
phMin = psMin = pvMin = phMax = psMax = pvMax = 0

while(1):
    # Get current positions of all trackbars
    hMin = cv2.getTrackbarPos('HMin', 'image')
    sMin = cv2.getTrackbarPos('SMin', 'image')
    vMin = cv2.getTrackbarPos('VMin', 'image')
    hMax = cv2.getTrackbarPos('HMax', 'image')
    sMax = cv2.getTrackbarPos('SMax', 'image')
    vMax = cv2.getTrackbarPos('VMax', 'image')

    # Set minimum and maximum HSV values to display
    lower = np.array([hMin, sMin, vMin])
    upper = np.array([hMax, sMax, vMax])

    # Convert to HSV format and color threshold
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower, upper)
    result = cv2.bitwise_and(image, image, mask=mask)

    # Print if there is a change in HSV value
    if((phMin != hMin) | (psMin != sMin) | (pvMin != vMin) | (phMax != hMax) | (psMax != sMax) | (pvMax != vMax) ):
        print("(hMin = %d , sMin = %d, vMin = %d), (hMax = %d , sMax = %d, vMax = %d)" % (hMin , sMin , vMin, hMax, sMax , vMax))
        phMin = hMin
        psMin = sMin
        pvMin = vMin
        phMax = hMax
        psMax = sMax
        pvMax = vMax

    # Display result image
    cv2.imshow('image', result)
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

c~视觉~CV~合集1_视觉_34

编辑

c~视觉~CV~合集1_视觉_35

编辑

c~视觉~CV~合集1_视觉_36

编辑

c~视觉~CV~合集1_视觉_37

编辑

五、CVの检测并计算直线角度

    检测线可用于各种类型的应用,例如机器人导航、无人机导航、运动分析和交通管理。本文我们将使用HoughLinesP函数来检测线条并从线条中提取角度。

c~视觉~CV~合集1_视觉_38

编辑

检测线

    想象一下,您想要创建一架无人机或一辆可以沿着路线行驶的简单汽车。事实上,创造和使用它似乎很有趣。或者您可能想跟踪道路上的线路并根据车道对汽车进行分类。对于这些类型的程序,您需要检测线条,并且可能需要根据您的目的提取角度。OpenCV 提供了多种检测直线和提取角度的函数:

  • HoughLines()
  • HoughLinesP()

选择合适的功能

    HoughLinesP可以检测碎片或不连续线(例如图像中的虚线或线段)时更有效。它提供有关检测到的线路的更多详细信息。

    HoughLines更适合检测完整、连续的线条。当检测图像中长的、不间断的线条时,它非常有用。

    我们需要一种可以检测各种形状的线条的算法,而不仅仅是直线。例如,如果道路向右成 45 度角,则 HoughLines() 函数在这种情况下可能无效。因此,我将使用HoughLinesP()函数

HoughLinesP() 函数如何工作?

    我不会深入研究该HoughLinesP()函数的数学细节,因为 Google 或 Youtube 等平台上有很多可用的资源。下面简单解释一下该HoughLinesP()函数的工作原理:

    OpenCV 中的函数HoughLinesP使用概率霍夫变换来检测图像中的线段。

  • 从边缘检测开始提取潜在的线点,然后进行投票过程来识别经过这些点的线,在参数空间中累积投票。
  • 参数空间是霍夫变换累积投票以检测图像中的线条的地方,每个维度代表被检测模型的一个参数,例如线条的斜率和截距。
  • 在阈值化选择突出线之后,它提取由端点表示的线段,提供有关其位置和长度的详细信息。

    这种方法可有效检测碎片或不连续的线,例如虚线或线段,与传统方法(如HoughLines.

HoughLinesP() 函数的参数

HoughLinesP(image, rho, theta, threshold,minLineLength,maxLineGap)

  • image:8 位、单通道输入图像。
  • rho:累加器的距离分辨率(以像素为单位)。(1在大多数情况下是有效的)
  • theta:累加器的角度分辨率(以弧度为单位)。(np.pi/180)
  • 阈值:简单的阈值。较高的阈值会导致线条更少但更准确,而较低的阈值会产生相反的效果。设置此参数的最佳方法是尝试不同的值。这完全取决于您的目的。
  • minLineLength:最小行长度。
  • maxLineGap:同一直线上的点之间允许的最大间隙以链接它们。

选择这些参数(Threshold、minLineLength 和 maxLineGap)的最佳方法是尝试不同的值组合。这些参数没有通用的最佳值;它们取决于图像的具体特征和期望的结果。

检测直线时如何使用提取的角度?

    想象一下算法从直线中提取出 67 度角。等式为:

direction_x = cos(extracted_angle=67) → velocity_x=1*direction_x

direction_y = sin(extracted_angle=67) → velocity_y=1*direction_y

c~视觉~CV~合集1_视觉_39

编辑

步骤/代码

    1. 读取图像并将其转换为灰度

    2. 使用 Canny 边缘检测器提取边缘。  

    3. 对Canny边缘检测后得到的图像应用HoughLinesP函数。

    4. 获取 HoughLinesP 函数的输出,对其进行迭代,绘制线条,并使用简单的公式提取角度。

Canny 边缘检测

aiot http://143ai.com

    Canny 边缘检测器有助于识别图像中的边缘

c~视觉~CV~合集1_视觉_40

编辑

检测直线并计算角度代码:

# read image
image = cv2.imread("resources/blog1.png")
# conert image to gray
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# extract edges with canny edge detector
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

# apply HoughLinesP
# cv2.HoughLinesP() returns an array of lines detected in the image.
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=75, minLineLength=100, maxLineGap=20)

if lines is not None:
    for i, line in enumerate(lines):
        x1, y1, x2, y2 = line[0]
        dy = (y2 - y1)
        dx = (x2 - x1)
        # convert radian to degree and extract angle
        angle = np.rad2deg(np.arctan2(dy, dx))
        
        # Since the Y-axis increases downwards(in opencv), invert the angle.
        angle = 180 - angle if angle > 0 else -angle
        
        # different color for every line
        color = tuple(np.random.randint(0, 255, 3).tolist())
        
        # detected line
        cv2.line(rgb_image, (x1, y1), (x2, y2), color, 3)
        # draw shape to starting and finishing points of lines
        cv2.putText(rgb_image, '>', (x1, y1), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 3)
        cv2.putText(rgb_image, '<', (x2, y2), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 3)
        # angle
        cv2.putText(rgb_image, str(round(angle, 1)),(x1 , int((y1+y2)/2)), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 3)

plt.imshow(rgb_image)

c~视觉~CV~合集1_视觉_41

编辑

编辑



标签:img,image,cv2,编辑,np,视觉,合集,CV,255
From: https://blog.51cto.com/whaosoft/11909352

相关文章

  • c~视觉~CV~合集2
     哈哈准备开始挪一些cv相的合集~ 一、CVの图像转为ASCII艺术效果   在广阔且不断扩展的编码项目领域中,那些将艺术与技术融为一体的人占据着特殊的地位。其中一个项目是从数字图像创建ASCII艺术图——这一过程将普通图片变成ASCII标准字符的马赛克。这是探索计算机视觉......
  • c~视觉~CV~合集3
     哈哈准备开始挪一些cv相的合集~ 一、CVの白平衡算法介绍OpenCV自带的三种白平衡算法使用--4.7版本OpenCVxphoto模块中提供了三种不同的白平衡算法,分别是:灰度世界算法、完美反射算法和基于学习的白平衡算法。本文将介绍其使用方法并给出代码演示,供大家参考。因为xphoto模组是......
  • 流媒体技术革新,EasyCVR视频汇聚平台赋能视频监控全面升级
    随着科技的飞速发展,流媒体技术和视频监控正经历着前所未有的变革与融合。本文将从流媒体技术的新兴趋势出发,探讨其与视频监控领域的深度结合,以及这一融合所带来的创新与发展。一、流媒体技术的新兴趋势1、5G网络的广泛应用5G网络以其高速率、低时延和大带宽的特性,为流媒体技术......
  • 从监控到智能:EasyCVR视频汇聚平台助力加油站安全监管升级转型
    随着科技的不断进步,视频监控技术在各个行业的应用日益广泛,尤其在加油站这一关键领域,视频智能监管系统的应用显得尤为重要。TSINGSEE青犀视频EasyCVR视频汇聚平台作为一款基于“云-边-端”一体化架构的视频融合与AI智能分析平台,在加油站视频智能监管中展现出了卓越的性能和广泛的应......
  • 智慧安防EasyCVR新版本(V3.6.0)播放鉴权与播放限制时长的区别介绍
    随着科技的飞速发展,视频技术已成为现代社会不可或缺的一部分,广泛应用于安防监控、娱乐传播、在线教育、电商直播等多个领域。EasyCVR视频汇聚平台作为视频技术的佼佼者,不断推陈出新,通过功能更新迭代,为用户提供更加高效、智能、稳定的视频解决方案。有用户部署EasyCVR视频汇聚平......
  • 安防视频EasyCVR视频汇聚平台集群部署出现状态不同步的情况是什么原因?
    随着视频监控技术的快速发展,各类视频资源的整合、管理与分发成为了安防行业的重要挑战。视频综合管理系统EasyCVR视频汇聚平台通过集群部署,实现了视频资源的高效整合与管理。集群部署不仅能够提升系统的处理能力和稳定性,还能有效避免单点故障,保障视频服务的连续性。有用户反馈,Ea......
  • 部标JT808标准下的视频汇聚新方案:EasyCVR平台助力推动车辆监管智能化进程
    在数字化转型的浪潮中,智慧城市的建设正以前所未有的速度推进,而市政车载设备作为城市运行的重要“神经末梢”,其智能化、联网化水平直接影响着城市管理效率与服务质量。近年来,随着部标协议(即国家行业标准协议)的广泛应用,市政车载设备迎来了接入与数据汇聚的新篇章,为构建更加智慧、高......
  • jsp安康学院公益平台6f3cv
    jsp安康学院公益平台6f3cv本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能用户,活动类型,活动报名,活动信息,取消报名,受惠者,捐款信息,用户捐款技术要求:   开发语言:JSP前端使用:HTML5,CSS,JSP......
  • vue3使用路由守卫出现的问题合集
    登录后停留在登录页面无法跳转--24.9.3原代码:functionisRoute(to){letres=router.getRoutes()letresFil=res.filter(item=>item.path===to.path)returnresFil.length>0}router.beforeEach((to,from,next)=>{if(to.path!=='/login'......
  • 视觉SLAM十四讲学习笔记-非线性优化的状态估计问题
    视觉SLAM十四讲学习笔记-非线性优化的状态估计问题经典SLAM模型的位姿可以由变换矩阵来描述,然后用李代数进行优化。观测方程由相机成像模型给出,其中内参是随相机固定的,而外参则是相机的位姿。由于噪声的存在,运动方程和观测方程的等式必定不是精确成立的。得到的数据通常是......