写出opencv源代码啥水平
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写出opencv源代码啥水平相关的知识,希望对你有一定的参考价值。
参考技术A 为了更好的成像质量引入的透镜导致了图像的畸变,无论是在摄影还是在AI图像识别方面都有还原事物真实面目的需求。那么我们首先体验一下在opencv中去畸变的快感吧。(偷偷说一下上面那张图是在ps中去畸变的 )opencv中去畸变有两种形式,一种直接调用cv::undistort()函数,函数参数如下:
@param src Input (distorted) image.@param dst Output (corrected) image that has the same size and type as src .@param cameraMatrix Input camera matrix \f$A = \vecthreethreef_x0c_x0f_yc_y001\f$ .@param distCoeffs Input vector of distortion coefficients\f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])\f$of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed.@param newCameraMatrix Camera matrix of the distorted image. By default, it is the same ascameraMatrix but you may additionally scale and shift the result by using a different matrix. */CV_EXPORTS_W void undistort( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, InputArray newCameraMatrix = noArray() );
此法对每帧图像去畸变都要计算复杂的公式,耗时非常多,因此在实时视频处理方面,没人用它。
使用 OpenCV 的光流 - 水平和垂直组件
【中文标题】使用 OpenCV 的光流 - 水平和垂直组件【英文标题】:Optical Flow using OpenCV - Horizontal and Vertical Components 【发布时间】:2014-12-25 05:14:59 【问题描述】:我有以下代码可以找到 2 个图像(或 2 个视频帧)的光流,并且它是彩色编码的。我想要的是光流的水平和垂直分量分别(如在单独的图像中)
这是我目前的代码:
import cv2
import numpy as np
frame1 = cv2.imread('my1.bmp')
frame2 = cv2.imread('my2.bmp')
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prvs, next, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2
hsv[...,2] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX)
rgb = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)
cv2.imshow('frame2',rgb)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv2.imwrite('opticalmyhsv.pgm',rgb)
cap.release()
cv2.destroyAllWindows()
这是给定我的两张图像的光流:
【问题讨论】:
这看起来像你从教程中提取了这段代码:docs.opencv.org/trunk/doc/py_tutorials/py_video/py_lucas_kanade/… - 无论如何,我会写一个答案。给我一点时间。 您使用的是相同的光流算法吗? OF算法有很多。另外,我怀疑他们是在一种算法而不是另一种算法中进行规范化。听起来 120-160 是用于将结果可视化为灰度图像,而5.232
是实际位移。
这可能就是它与众不同的原因。不是同一个算法。除非我知道场景中的最小和最大原始位移,否则我不知道如何将其恢复到位移。请发布一个单独的问题。这超出了您对这个的要求。
我已回滚您的编辑。请不要删除代码和图像。这对您问题的未来访问者很有用。这也将有助于理解我写给你的答案。没有这两件事,人们不会知道发生了什么。
【参考方案1】:
如果您想分别可视化水平和垂直分量,您可以将两者分别可视化为灰度图像。我会让灰色表示没有运动,黑色表示向左的帧中的最大运动量(负),而白色表示向右的帧中的最大运动量(正) .
calcOpticalFlowFarneback
的输出是一个 3D numpy
数组,其中第一个切片表示水平 (x
) 位移量,而第二个切片表示垂直 (y
) 位移量。
因此,您需要做的就是定义两个单独的 2D numpy
数组来存储这些值,以便我们可以将它们显示给用户。但是,您需要对显示流进行标准化,以便没有运动是粗灰色,最左边的运动是黑色或强度 0,而最右边的运动是白色或强度 255。
因此,您需要做的就是修改代码以显示两个 OpenCV 窗口,用于水平和垂直运动,如下所示:
import cv2
import numpy as np
frame1 = cv2.imread('my1.bmp')
frame2 = cv2.imread('my2.bmp')
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)
next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(prvs, next, 0.5, 3, 15, 3, 5, 1.2, 0)
# Change here
horz = cv2.normalize(flow[...,0], None, 0, 255, cv2.NORM_MINMAX)
vert = cv2.normalize(flow[...,1], None, 0, 255, cv2.NORM_MINMAX)
horz = horz.astype('uint8')
vert = vert.astype('uint8')
# Change here too
cv2.imshow('Horizontal Component', horz)
cv2.imshow('Vertical Component', vert)
k = cv2.waitKey(0) & 0xff
if k == ord('s'): # Change here
cv2.imwrite('opticalflow_horz.pgm', horz)
cv2.imwrite('opticalflow_vert.pgm', vert)
cv2.destroyAllWindows()
我已经修改了代码,因此没有while
循环,因为您只能找到两个预定帧之间的光流。您不会从实时源(例如相机)中抓取帧,因此我们可以只显示不在while
循环中的两个图像。我已将 waitKey
的等待时间设置为 0,以便您无限期地等待直到您按下一个键。这几乎模拟了您之前的 while
循环行为,但它不会因浪费的周期而不必要地加重您的 CPU 负担。我还删除了一些不必要的变量,例如 hsv
变量,因为我们没有同时显示颜色编码的水平和垂直分量。我们也只计算一次光流。
无论如何,我们用上面的代码计算光流,分别提取水平和垂直分量,对[0,255]
范围内的分量进行归一化,转换为uint8
,这样我们就可以显示结果然后显示结果。我还修改了你的代码,如果你想保存组件,它会将水平和垂直组件保存为两个单独的图像。
编辑
在您的 cmets 中,您希望使用我们在上面创建的相同逻辑来显示一系列图像。您有一个要循环浏览的文件名列表。这不是很难做到。只需将您的字符串放入列表中,然后使用存储在此列表中的文件名计算成对图像之间的光流。我将修改代码,以便当我们到达列表的最后一个元素时,我们将等待用户推送某些内容。在那之前,我们将循环浏览每对图像,直到结束。换句话说:
import cv2
import numpy as np
# Create list of names here from my1.bmp up to my20.bmp
list_names = ['my' + str(i+1) + '.bmp' for i in range(20)]
# Read in the first frame
frame1 = cv2.imread(list_names[0])
prvs = cv2.cvtColor(frame1,cv2.COLOR_BGR2GRAY)
# Set counter to read the second frame at the start
counter = 1
# Until we reach the end of the list...
while counter < len(list_names):
# Read the next frame in
frame2 = cv2.imread(list_names[counter])
next = cv2.cvtColor(frame2,cv2.COLOR_BGR2GRAY)
# Calculate optical flow between the two frames
flow = cv2.calcOpticalFlowFarneback(prvs, next, 0.5, 3, 15, 3, 5, 1.2, 0)
# Normalize horizontal and vertical components
horz = cv2.normalize(flow[...,0], None, 0, 255, cv2.NORM_MINMAX)
vert = cv2.normalize(flow[...,1], None, 0, 255, cv2.NORM_MINMAX)
horz = horz.astype('uint8')
vert = vert.astype('uint8')
# Show the components as images
cv2.imshow('Horizontal Component', horz)
cv2.imshow('Vertical Component', vert)
# Change - Make next frame previous frame
prvs = next.copy()
# If we get to the end of the list, simply wait indefinitely
# for the user to push something
if counter == len(list_names)-1
k = cv2.waitKey(0) & 0xff
else: # Else, wait for 1 second for a key
k = cv2.waitKey(1000) & 0xff
if k == 27:
break
elif k == ord('s'): # Change
cv2.imwrite('opticalflow_horz' + str(counter) + '-' + str(counter+1) + '.pgm', horz)
cv2.imwrite('opticalflow_vert' + str(counter) + '-' + str(counter+1) + '.pgm', vert)
# Increment counter to go to next frame
counter += 1
cv2.destroyAllWindows()
上面的代码将循环显示成对的帧,并在每对帧之间等待 1 秒,让您有机会退出显示,或将水平和垂直组件保存到文件中。请记住,我已经做到了,无论您保存什么帧,它们都会用两个数字编制索引,告诉您它们正在显示哪些帧对。在下一次迭代发生之前,下一帧将是上一帧,因此next
被prvs
的副本替换。在循环开始时,下一帧被适当地读入。
希望这会有所帮助。祝你好运!
【讨论】:
calcOpticalFlowPyrLK()
是 OpenCV 中的 Lucas-Kanade 算法,它不会为您提供水平和垂直位移的二元素元组。只是说。
@a-Jays - 哎呀。我的错。在本例中,它是一个 3D numpy
数组。我显然无法阅读文档。修正了我的答案。
@Rohit - 您可以像以前一样在while
循环中显示所有这些。我会发布一个编辑。
我还没来得及写答案。毕竟是圣诞节!我很快就会的。
@Rohit - 完成。祝你好运!以上是关于写出opencv源代码啥水平的主要内容,如果未能解决你的问题,请参考以下文章
详解OpenCV的坐标重映射函数remap()的两种使用方法并附使用它得到图像的水平镜像和垂直镜像的示例代码