-
转自公众号:小白学视觉图像处理之理解Homography matrix(单应性矩阵)单应性矩阵是投影几何中一个术语,本质上它是一个数学概念,但是在OpenCV中却是有几个函数与透视变换相关的函数,都用到了单应性矩阵的概念与知识。小编跟很多人一样,刚开始学习图像处理对单应性矩阵不是很了解,通过项目实践慢慢知道了一些这方面的知识和自己对它的理解,就跟大家分享一下。单应性矩阵概念这里说的单应性矩阵主要是指平面单应性矩阵,在三轴坐标中XYZ,Z=1这个有点类似于三维的齐次坐标。单应性矩阵主要用来解决两个问题,一是表述真实世界中一个平面与对应它图像的透视变换二是从通过透视变换实现图像从一种视图变换到另外一种视图首先看一下在三维空间中任意两个平面上图的中零点分别表示两个平面中任意两个点,a1、a2与b1、b2是这两点对应的两个方向上的线性向量。对于这两个平面直接的关系我们就可以通过这些点从而进一步确立两个平面直接的关系,而两个平面之间的关系用单应性矩阵来描述如下:这种关系被称为平面单应性。这个当中有一些数学知识推导,感兴趣的大家可以自己去看,我们最重要的是明白这个概念怎么来的。其次知道它的应用场景,下面我们就从应用层面和代码层面来说说单应性矩阵的应用。 - 用来解决拍照时候图像扭曲问题。这个在上一篇文章透视 变换中讲过,但是 当时没有说这个是单应性矩阵的应用。- 此外还两个计算机图形学的应用场景分布是纹理渲染与计算平面阴影。- 用来实现图像拼接时候解决对齐问题应用案例街拍的时候路两边有很多广告牌,如果在视频实时帧中获取到对应的广告牌位置,就可以获取广告牌的四个角坐标,然后通过准备好的内容,将广告牌内容替换,得到想要的虚拟广告牌效果,而这个过程中最重要的一步,可以通过计算单应性矩阵实现内容替换,演示效果如下: 时代广场的街拍看到左侧的广告牌不,我们准好了一张图像,准备替换它的内容,准备的图像如下:最终处理之后的效果如下:实现代码如下:#include #include #include using namespace cv;using namespace std;int main(int argc, char** argv) { // load images Mat src = imread("D:/vcprojects/images/times-square.jpg"); if (!src.data) { printf("could not load image..."); return -1; } // show images namedWindow("input image", CV_WINDOW_AUTOSIZE); imshow("input image", src); Mat replaceImg = imread("D:/vcprojects/images/kgirls.png"); imshow("adv content", replaceImg); // 定义两个平面上四个角坐标 vector src_corners(4); vector dst_corners(4); // 原图像平面四点坐标 src_corners[0] = Point(0, 0); src_corners[1] = Point(replaceImg.cols, 0); src_corners[2] = Point(0, replaceImg.rows); src_corners[3] = Point(replaceImg.cols, replaceImg.rows); // 目标平面四个角坐标 dst_corners[0] = Point(70, 131); dst_corners[1] = Point(168,216); dst_corners[2] = Point(21, 199); dst_corners[3] = Point(148, 267); // 计算单应性矩阵与透视变换 Mat h = findHomography(src_corners, dst_corners); Mat output_img; warpPerspective(replaceImg, output_img, h, src.size()); // create mask Mat m1 = Mat::zeros(replaceImg.size(), CV_8UC1); m1 = Scalar(255); Mat mask_output; warpPerspective(m1, mask_output, h, src.size()); imshow("Mask Result", mask_output); // use mask Mat result1; add(output_img, output_img, result1, mask_output); Mat result2; bitwise_not(mask_output, mask_output); add(src, result1, result2, mask_output); // put them together Mat result; add(result1, result2, result); imshow("Final Result", result); imwrite("D:/vcprojects/images/result.png", result); waitKey(0); return 0;}
-
将把文本图像与漂亮的背景图像混合在一起。让我们先来看看这两个图像:   bg = cv2.imread('images/background.jpg', cv2.IMREAD_COLOR) fg = cv2.imread('images/foreground.png', cv2.IMREAD_COLOR) 我们先调整图像大小,以确保它们的尺寸相同。要使融合能够正常进行,需要使用相同的大小图像。否则,它将返回错误消息。 (.shape)背景图像为853到1280像素。前景图像为1440至2560像素。我们将使用OpenCV的调整大小功能调整它们的大小。 dim = (1200, 800) resized_bg = cv2.resize(bg, dim, interpolation = cv2.INTER_AREA) resized_fg = cv2.resize(fg, dim, interpolation = cv2.INTER_AREA) 有了OpenCV,我们可以用一行代码来完成这项工作。将为我们完成混合的功能称为addWeighted。它有5个参数,可以列出为:图像源1,src1权重,图像源2,src2权重,伽玛。每个图像的权重值必须小于1。这是混合方程式: blend = (image scr1)*(src1 weight) + (image scr2)*(src2 weight) + gamma 这是函数的数学原理。让我们看看实际情况: `blend = cv2.addWeighted(resized_bg, 0.5, resized_fg, 0.8, 0.0)` 我们给前景加了一些权重。这样,背景将更暗,文本将更亮。 现在,让我们使用imwrite方法导出最终作品。这是将图像另存为文件夹中的新图像文件的行。 `cv2.imwrite('blended.png', blend)` 
-
OpenCV 中国镜像仓:https://gitcode.net/opencvOpenCV是一个基于Apache 2.0 许可证(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、macOS、Android和iOS操作系统上。为了解决克隆 OpenCV 源码以及构建过程的下载问题,OpenCV 中国团队联系了国内一家提供代码托管服务的网站 GitCode.net,双方对 OpenCV 中国镜像的想法一拍即合,为广大 OpenCV 的开发者提供便利。这样下载就不会慢了~
-
本文转自:opcv学堂本文来自光头哥哥的博客【Measuring distance between objects in an image with OpenCV】,仅做学习分享。原文链接:https://www.pyimagesearch.com/2016/04/04/measuring-distance-between-objects-in-an-image-with-opencv/已经完成了测量物体大小的任务,今天进行最后一部分:计算图片中物体之间的距离。上篇我们讨论了如何使用参考对象来测量图像中对象的大小。这个参考对象应该有两个重要的特征,包括:• 我们知道这个物体的尺寸(以英寸、毫米等表示)。• 它很容易在我们的图像中被识别出来(根据位置或外观)。给定这样一个参考对象,我们可以使用它来计算图像中对象的大小。今天,我们将结合本系列前两篇来计算对象之间的距离。计算物体之间的距离与计算图像中物体的大小算法思路非常相似——都是从参考对象开始的。我们将使用0.25美分作为我们的参考对象,它的宽度为0.955英寸。并且我们还将0.25美分总是放在图片最左侧使其容易识别。这样它就满足了我们上面提到的参考对象的两个特征。我们的目标是找到0.25美分,然后利用0.25美分的尺寸来测量0.25美分硬币与所有其他物体之间的距离。定义参考对象并计算距离打开一个新文件,将其命名为distance_between.py,插入以下代码: # import the necessary packages from scipy.spatial import distance as dist from imutils import perspective from imutils import contours import numpy as np import argparse import imutils import cv2 def midpoint(ptA, ptB): return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5) # construct the argument parse and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to the input image") ap.add_argument("-w", "--width", type=float, required=True, help="width of the left-most object in the image (in inches)") args = vars(ap.parse_args())# import the necessary packages我们这里的代码与上周的代码几乎相同。我们从在第2-8行上导入所需的Python包开始。 第12-17行解析命令行参数。这里我们需要两个参数:——image,它是包含我们想要测量的对象的输入图像的路径,以及——width,为我们参考对象的宽度(单位为英寸)。接下来,我们需要对图像进行预处理:# load the image, convert it to grayscale, and blur it slightly image = cv2.imread(args["image"]) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (7, 7), 0) # perform edge detection, then perform a dilation + erosion to # close gaps in between object edges edged = cv2.Canny(gray, 50, 100) edged = cv2.dilate(edged, None, iterations=1) edged = cv2.erode(edged, None, iterations=1) # find contours in the edge map cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) # sort the contours from left-to-right and, then initialize the # distance colors and reference object (cnts, _) = contours.sort_contours(cnts) colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0), (255, 0, 255)) refObj = None第2-4行从磁盘加载图像,将其转换为灰度图,然后使用7 x 7内核的高斯滤波器对其进行模糊降噪。当我们的图像被模糊后,我们应用Canny边缘检测器来检测图像中的边缘,然后进行膨胀+腐蚀来缩小边缘图中的缝隙(第7-9行)。调用cv2.findContours检测边缘图中对象的轮廓(第11-13行),而第16行从左到右对轮廓进行排序。由于我们知道0.25美分(即参考对象)将始终是图像中最左边,因此从左到右对轮廓进行排序可以确保与参考对象对应的轮廓始终是cnts列表中的第一个。然后,我们初始化用于绘制距离的colors列表以及refObj变量,该变量将存储参考对象的边界框、质心和pixels-per-metric值(看上一篇就明白pixels-per-metric的具体定义,其实就是参考对象的实际大小(单位英寸)与图片中的宽度(单位为像素)的比值)。# loop over the contours individually for c in cnts: # if the contour is not sufficiently large, ignore it if cv2.contourArea(c) < 100: continue # compute the rotated bounding box of the contour box = cv2.minAreaRect(c) box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box) box = np.array(box, dtype="int") # order the points in the contour such that they appear # in top-left, top-right, bottom-right, and bottom-left # order, then draw the outline of the rotated bounding # box box = perspective.order_points(box) # compute the center of the bounding box cX = np.average(box[:, 0]) cY = np.average(box[:, 1])xxxxxxxxxx # loop over the contours individually# loop over the contours individuallyfor c in cnts: # if the contour is not sufficiently large, ignore itif cv2.contourArea(c) < 100:continue # compute the rotated bounding box of the contourbox = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)box = np.array(box, dtype="int") # order the points in the contour such that they appear # in top-left, top-right, bottom-right, and bottom-left # order, then draw the outline of the rotated bounding # boxbox = perspective.order_points(box) # compute the center of the bounding boxcX = np.average(box[:, 0])cY = np.average(box[:, 1])在第2行,我们开始对cnts列表中的每个轮廓进行循环。如果轮廓比较小(第4和5行),我们认为是噪声并忽略它。 然后,第7-9行计算当前对象的最小旋转包围框。第14行上调用order_points函数(此系列第一篇定义的函数)来对矩形框四个顶点以左上角、右上角、右下角和左下角的顺序排列,我们将看到,在计算物体之间的距离时,这一点非常重要。第16行和第17行通过取边界框在x和y方向上的平均值来计算旋转后的边界框的中心(x, y)坐标。下一步是校准我们的refObj:# if this is the first contour we are examining (i.e., # the left-most contour), we presume this is the # reference object if refObj is None: # unpack the ordered bounding box, then compute the # midpoint between the top-left and top-right points, # followed by the midpoint between the top-right and # bottom-right (tl, tr, br, bl) = box (tlblX, tlblY) = midpoint(tl, bl) (trbrX, trbrY) = midpoint(tr, br) # compute the Euclidean distance between the midpoints, # then construct the reference object D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY)) refObj = (box, (cX, cY), D / args["width"]) continue如果refObj为None(第4行),则需要对其进行初始化。 我们首先获取(排序后的)最小旋转边界框坐标,并分别计算四个顶点之间的中点(第10-15行)。然后计算中点之间的欧氏距离,给出我们的“像素/尺寸”比例,来确定一英寸为多少像素宽度。最后,我们将refObj实例化为一个3元组,包括:• 物体对象的最小旋转矩形对象box• 参考对象的质心。• 像素/宽度比例,我们将用其来结合物体之间的像素距离来确定物体之间的实际距离。下一个代码块负责绘制参考对象和当前检查对象的轮廓,然后定义变量refCoords和objCoords,这样(1)最小包围矩阵坐标和(2)质心的(x, y)坐标都包含在同一个数组中:# draw the contours on the image orig = image.copy() cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2) cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2) # stack the reference coordinates and the object coordinates # to include the object center refCoords = np.vstack([refObj[0], refObj[1]]) objCoords = np.vstack([box, (cX, cY)])现在我们可以开始计算图像中各个物体的质心和质心之间的距离了: # loop over the original points for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors): # draw circles corresponding to the current points and # connect them with a line cv2.circle(orig, (int(xA), int(yA)), 5, color, -1) cv2.circle(orig, (int(xB), int(yB)), 5, color, -1) cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)), color, 2) # compute the Euclidean distance between the coordinates, # and then convert the distance in pixels to distance in # units D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2] (mX, mY) = midpoint((xA, yA), (xB, yB)) cv2.putText(orig, "{:.1f}in".format(D), (int(mX), int(mY - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2) # show the output image cv2.imshow("Image", orig) cv2.waitKey(0)在第2行,我们开始对图片中物体对象的顶点(x, y)坐标进行循环。 然后我们画一个圆表示我们正在计算距离的当前点坐标,并画一条线连接这些点(第5-7条线)。然后,第12行计算参考位置和对象位置之间的欧式距离,然后除以“像素/度量”,得到两个对象之间的实际距离(以英寸为单位)。然后在图像上标识出计算的距离(第13-15行)。距离测量结果下面是一个GIF动画,演示了我们的程序运行效果: 在每种情况下,我们的脚本都匹配左上(红色)、右上(紫色)、右下(橙色)、左下(蓝绿色)和质心(粉色)坐标,然后计算参考对象和当前对象之间的距离(以英寸为单位)。注意图像中的两个0.25美分完全平行,这意味着所有五个顶点之间的距离均为6.1英寸。下面是第二个例子,这次计算的是参考对象和药丸之间的距离: 这个例子可以作为药片分类机器人的输入,自动获取一组药片,并根据它们的大小和与药片容器的距离来组织它们。 最后一个例子计算了我们的参考对象(一张3.5英寸x 2英寸的名片)和一组7英寸的黑胶唱片和信封之间的距离:
-
计算机视觉是最令人兴奋的领域之一,其应用范围非常广泛。从医学成像到创建最有趣的面部滤镜等各个领域都充分见证了计算机视觉技术的强大。在本文中,我们将尝试创建一个人造眼线笔来模仿Snapchat或Instagram滤波器,为视频中的美女添加上美丽的眼线。最终的结果可以通过下面的动图观察到。本文介绍的内容适合想要通过计算机视觉来实现一个具有一定展示性功能的计算机视觉初学者。因此,在本文重我们会尽量简化说明,如果您对完整的程序感兴趣,可以在Github上找到完整的代码。Github的链接在本文的文末给出。 在实现本文功能之前,我们需要设置一个新的虚拟环境并安装所有必需的依赖项。这个过程比较简单,我们也在Github里面给出了如何配置环境的具体过程。在本项目中,我们需要使用的工具有OpenCV,NumPy,imutils,SciPy和Dlib。有些小伙伴可能对这些工具和库比较陌生,接下来我们简单介绍一下每个模块的作用。• OpenCV:用于图像处理的最受欢迎的模块之一。我们将使用OpenCV读取,写入和绘制图像。• NumPy:在处理OpenCV项目时经常使用NumPy。图像本质上是一个像素数组,OpenCV使用以NumPy数组形式存储的这些数组,并对图像执行操作。• Imutils:Imutils附带了自定义功能,使我们的计算机视觉工作变得更加轻松。在这里,我们将使用它来将dlib对象转换为非常灵活且广泛接受的numpy数组。• Scipy:顾名思义,SciPy用于python上的科学计算。我们将使用它来创建插值(如果现在没有意义,可以的)。• Dlib:Dlib是一个包含各种ML算法的C ++库。我们将使用dlib提取面部界标点。项目简要介绍该程序首先从每个面孔中提取68个界标点。在这68个点中,点37–42属于左眼,点43–48属于右眼,具体形式如下图所示。因为我们的目标是给面部添加眼线,所以我们只对37-48点感兴趣,因此我们提取了这些点。我们将对这些提取的点进行插值。插值意味着我们尝试在两个给定点之间插入点。我们可以使用的插值方式如下图所示。眼线算法的流程图如下所示接下来,我们将进一步详细描述该算法。如果小伙伴只对运行代码感兴趣,可以跳至最后一部分。算法介绍我们首先需要提取脸部周围边界框的坐标。OpenCV将图像转换为NumPy数组。numpy.array(即图像的矩阵表示形式)存储在名为的变量中frame。我们使用一个名为face_detector()的函数,该函数返回围绕框架中所有脸部的包围框的坐标。这些边界框坐标存储在一个名为bounding_boxes的变量中。遍历循环bounding_boxes以将眼线应用于帧中检测到的每个脸部。face_landmark_points存储68个坐标点。eye_landmark_points是从getEyeLandmarkPts()函数中得到。getEyeLandmarkPts()函数使用68个坐标点作为输入并返回具有左上眼睑的坐标4个矩阵,左上眼线(L_eye_top),左下眼线(L_eye_bottom)和相同的右眼(R_eye_top & R_eye_bottom)。这可以通过简单的NumPy索引完成的。我们将端点(pt号37、40、43和46。请参见68个界标点图)向外移动5px,以使外观更逼真。现在,我们需要对这些点进行插值以获得平滑的曲线,进而可以画出眼线。我们需要对每个曲线进行不同的处理(即L_eye_top,L_eye_bottom,R_eye_top,R_eye_bottom)。因此,我们为每个曲线使用单独的变量名称。interpolateCoordinates()用于在每条曲线上生成插值。重复使用该函数,为每个曲线生成插值坐标。这个函数为每个曲线返回一个插值点数组。drawEyeLiner()函数将生成的插值点作为参数,并在两个连续点之间画一条线。在两个循环中为每个曲线完成此操作,一个循环用于左眼,另一个循环用于右眼。 调用项目该项目的用发非常简单,首先从Github上克隆到本地 git clone https://github.com/kaushil24/Artificial-Eyeliner/接下来,打开命令提示符并键入以下代码以运行示例测试python3 eyeliner.py -v "Media/Sample Video.mp4"我们也可以通过将视频路径放在参数中来使用自己的视频。完整的CLI命令如下:python eyeliner.py [-i image] [-v video] [-d dat] [-t thickness] [-c color] [-s save]每个参数的具体含义如下:• i :要在其上绘制眼线的图像的路径• v :要在其上绘制眼线的视频的路径。• v :也可以通过网络摄像头获取视频。例如:python3 -v webcam -s "Webcam output"• t :整数(整数)以设置眼线的厚度。默认值= 2。推荐的数值介于1-5之间• d:shape_predictor_68_face_landmarks.dat文件的路径。默认路径在根目录中。除非将shape_predictor_68_face_landmarks.dat文件存储在其他位置,否则不需要使用此参数。• c :更改眼线的颜色。语法-c 255 255 255。默认值= 0 0 0。其中每个数字代表其RGB值。• s :要将输出保存到的位置和文件名。注意程序在保存文件时会自动添加扩展名。如果已经存在同名文件,它将覆盖该文件。转载自小白学视觉公众号
-
现在,面部识别已成为生活中的一部分。因此,在介绍主题之前我们先看看实时面部识别示例。我们在手机、平板电脑等设备中使用人脸信息进行解锁的时候,这时就要求获取我们的实时面部图像,并将其储存在数据库中以进一步表明我们的身份。 通过对输入图像进行迭代和预测可以完成这个过程。同样,实时人脸识别可与OpenCV框架python的实现配合使用。再将它们组合在一个组合级别中,以实现用于实时目的的模型。 人脸识别 “面部识别”名称本身就是一个非常全面的定义,面部识别是通过数字媒体作为输入来识别或检测人脸的技术执行过程。人脸识别的准确性可以提供高质量的输出,而不是忽略影响其的问题因素。在这里,要确保运行我们的模型,必须确保在本地系统中安装了库。pip install face_recognition如果在 face_recognition库的安装过程中遇到一些问题或错误,可以点击以下链接:https://www.youtube.com/watch?v=xaDJ5xnc8dc人脸识别本身无法提供清晰的输出,因此出现了OpenCV实现的概念。OpenCV OpenCV是python中一个著名的库,用于实时应用程序。OpenCV在计算机世界中就像树的根一样非常重要。face_recognition中的OpenCV对我们训练为输入的面部图像进行聚类和特征提取。它以图像中的地标为目标,以迭代方式在计算机视觉的深度学习方法中训练它们。在本地系统中安装OpenCVpip install opencv-python使用深度学习算法,OpenCV检测可作为聚类,相似性检测和图像分类的表示。为什么我们使用OpenCV作为实时Face_Recognition中的关键工具? 人类可以轻松检测到面部,但是我们如何训练机器识别面部?OpenCV在这里填补了人与计算机之间的空白,并充当了计算机的愿景。以一个实时的例子为例,当一个人遇到新朋友时,他会记住这些人的脸,以备将来识别。一个人的大脑反复训练后端的人脸。因此,当他看到那个人的脸时,他说:“嗨,约翰!你好吗?”。对面部的识别和可以为计算机提供与人类相同的思维方式。OpenCV是计算机视觉中的重要工具。如果我们使用OpenCV,则遵循以下步骤:• 通过输入提取数据。• 识别图像中的面部。• 提取独特的特征,以建立预测思想。• 该特定人的性格特征,如鼻子,嘴巴,耳朵,眼睛和面部主要特征。• 实时人脸识别中人脸的比较。• 识别出的人脸的最终输出。使用OpenCV python的Face_Recognition: 代码下载:https://github.com/eazyciphers/deep-machine-learning-tutors/tree/master/Real-Time Face RecognitionGitHub导入所有软件包:import face_recognitionimport cv2import numpy as np加载并训练图像:# Load a sample picture and learn how to recognize it. Jithendra_image = face_recognition.load_image_file("jithendra.jpg") Jithendra_face_encoding = face_recognition.face_encodings(Jithendra_image)[0] # Load a sample picture and learn how to recognize it. Modi_image = face_recognition.load_image_file("Modi.jpg") Modi_face_encoding = face_recognition.face_encodings(Modi_image)[0]人脸编码:# Create arrays of known face encodings and their names known_face_encodings = [ Jithendra_face_encoding, Modi_face_encoding, ] known_face_names = [ "Jithendra", "Modi" ]主要方法:当实时人脸识别为true时,它将检测到人脸并按照代码中的以下步骤操作:• 抓取实时视频中的一帧。• 将图像从BGR颜色(OpenCV使用的颜色)转换为RGB颜色(face_recognition使用的颜色)• 在实时视频的帧中找到所有面部和面部编码。• 循环浏览此视频帧中的每个面孔,并检查该面孔是否与现有面孔匹配。• 如果一个人脸无法识别现有人脸,则将输出视为未知或未知。• 识别后,否则在识别出的脸部周围画一个方框。• 用其名称标记识别的面部。• 识别后显示结果图像。退出:# Hit 'q' on the keyboard to quit! if cv2.waitKey(1) & 0xFF == ord('q'): break释放摄像头的手柄:# Release handle to the webcam video_capture.release() cv2.destroyAllWindows()输入和输出 在训练过程中提供给模型的样本输入…。输入用于训练代码的样本图像样本输入图像进行训练输出
-
分割是识别图像内一个或多个对象的位置的过程。我们要介绍的技术其实非常简单,它利用了形态算子的扩张和侵蚀,以及诸如开运算,闭运算和黑帽算子的组合。01.简介安装Anaconda后,让我们从Anaconda的提示符下使用以下命令转到OpenCV安装:conda install -c https://conda.anaconda.org/menpo opencv现在,让我们从Anaconda启动器启动Spyder IDE。Anaconda启动器一旦运行了Spyder,建议验证OpenCV安装是否成功。在Python控制台的右下角,我们进行以下测试:import cv2代码讲解我们已经创建了一个启动GitHub存储库。小伙伴可以使用以下方法直接克隆它:git clone --branch step1 https://github.com/lucapiccinelli/BarcodesTutorial.git现在,我们将要下载测试图像,并对他们进行读取和显示。import cv2 import matplotlib.pyplot as plt im = cv2.imread(r’img\barcodes.jpg’, cv2.IMREAD_GRAYSCALE) plt.imshow(im, cmap=’Greys_r’)接下来,我们将对图像进行二值化处理,这样可以通过阈值的设定来提取出我们感兴趣的部分。使用黑帽运算符,我们可以增加较暗的图像元素。我们可以首先使用简单的全局阈值安全地对图像进行二值化处理。黑帽运算符使我们可以使用非常低的阈值,而不必过多地关注噪声。在应用blackhat时,我们使用的内核会更加重视垂直图像元素。内核具有固定的大小,因此可以缩放图像,这也可以提高性能(并支持某种输入归一化)。黑帽+阈值处理它遵循其他形态运算符的采用,顺序地将它们组合在一起以获得条形码位置中的连接组件。#riscalatura dell'immagine scale = 800.0 / im.shape[1] im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale))) #blackhat kernel = np.ones((1, 3), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel, anchor=(1, 0)) #sogliatura thresh, im = cv2.threshold(im, 10, 255, cv2.THRESH_BINARY)膨胀和闭合的这种组合在测试图像上效果很好,但可能无法在其他图像上达到相同的效果。这没有关系,大家可以尝试改变参数和运算符的组合,直到对结果满意为止。膨胀+闭运算最后的预处理步骤是应用具有很大内核的开运算符,以删除太少而无法适合条形码形状的元素。kernel = np.ones((21, 35), np.uint8) im = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel, iterations=1)这是我们希望得到的最终结果:使用35x21内核打开现在,我们可以运行连接的组件的检测算法,并检索带有坐标和尺寸的条形码矩形。如大家在上一张图像中所看到的那样,最后的形态学步骤并未滤除全部的噪声。但是,在这种情况下,将它们过滤掉非常简单,以矩形区域值作为阈值就可以了。#rilettura dell'immagine, stavolta a colori im_out = cv2.imread(r'img\barcodes.jpg') #estrazione dei componenti connessi contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) unscale = 1.0 / scale if contours != None: for contour in contours: # se l'area non è grande a sufficienza la salto if cv2.contourArea(contour) <= 2000: continue #estraggo il rettangolo di area minima (in formato (centro_x, centro_y), (width, height), angolo) rect = cv2.minAreaRect(contour) #l'effetto della riscalatura iniziale deve essere eliminato dalle coordinate rilevate rect = \ ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \ (int(rect[1][0] * unscale), int(rect[1][1] * unscale)), \ rect[2]) #disegno il tutto sull'immagine originale box = np.int0(cv2.cv.BoxPoints(rect)) cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness = 2) plt.imshow(im_out) #scrittura dell' immagine finale cv2.imwrite(r'img\out.png', im_out)最后,在上面的代码中,我使用提取的矩形绘制它们,并将其覆盖在原始图像上。最终结果,条形码以绿色框突出显示。结论• 提出的技术非常简单有效,但存在一些令人讨厌的缺点:• 它对条形码偏斜非常敏感;它可以很好地工作到大约45度,然后您必须执行第二遍,修改内核的方向。• 它只能在固定尺寸范围内找到条形码。• 尽管对矩形区域施加了过滤,但仍有可能无法清除某些非条形码。第一个和第二个可能不是真正的问题,但是最后一个可能会花费大家大量时间来尝试解码非条形码的内容。一个很好的解决方案是将条形码特征(图像梯度,傅立叶变换)输入给神经网络(或一些其他一些分类器),并在第二时刻过滤掉噪声。
-
计算机视觉现在很流行,世界各地的人们都在从事某种形式的基于深度学习的计算机视觉项目。但在深度学习出现之前,图像处理技术已被用来处理和转换图像,以获得有助于我们完成任务的见解。今天,让我们看看如何实现一种简单而有用的技术,即透视投影来扭曲图像。 那么扭曲图像是什么意思?我可以用很多花哨的词和技术术语来解释它。但是,展示最终结果很容易,这样我们就可以通过观察来学习。  基础图像——主题图像——扭曲的输出 所以基本上,我们需要拍摄一个图像并剪切它以使其适合任何所需形状的画布。请注意,反过来也是可能的。现在,这已经不成问题了,让我们就来看看如何使用 OpenCV 和 Python 来实现这一点。 在进入代码的主要部分之前,我们必须首先导入必要的库。 ``` import cv2 ``` 现在,让我们按如下方式读取基本图像和主题图像。 ``` base_image = cv2.imread('base_img.jpg') ```  基本图像(左)——主体图像(右) 初始化一个数组来存储我们想要覆盖主题图像的 4 个角的坐标,我们可以使用setMouseCallback()函数手动选择这 4 个点,如下所示。 ``` def click_event(event, x, y, flags, params): ``` 在上面给出的代码片段中,我们定义了一个名为click\_event()的函数,并将其作为参数传递给setMouseCallback()函数。使用这种方法,我们将首先显示基础图像,然后我们可以手动选择图像中的四个点作为目标。我们的主题图像会扭曲到这个目标上,按下鼠标左键时记录坐标,这些存储在我们之前初始化的点数组中。选定的点以红点突出显示,如下所示。  选择角点 众所周知,我们每个人都可以按任意顺序选择 4 个点。因此需要在所选点之间保持恒定的排序。我选择以顺时针方式对点进行排序,即从左上到右上,再到右下然后到左下,这是通过如下所示的sort\_pts()方法实现的。我们使用以下事实:x 和 y 坐标的总和在左上角最小,在右下角最大。同样,它们之间的差异在右上角最小,在左下角最大。请记住,对于图像,原点位于图像的左上角。 ``` def sort_pts(points): ``` 对点进行排序后,让我们用它们来计算变换矩阵。我们创建一个名为“pts1”的 numpy 数组,它保存了主题图像的四个角的坐标。同样,我们创建一个名为“pts2”的列表,其中包含已排序的点。“pts1”的坐标顺序应该与“pts2”坐标的顺序相匹配。 ``` h_base, w_base, c_base = base_image.shape ``` 现在我们获得了扭曲对象图像所需的变换矩阵。这是使用函数cv2.getPerspectiveTransform() 获得的。由于我们希望以适合我们在基础图像中选择的框的方式变化主题图像,因此“ src ”应为“ pts1 ”,“ dst ”应为“ pts2 ”。生成的图像的大小可以指定为元组。我们确保生成的图像具有基本图像的尺寸。使用生成的矩阵,我们可以使用cv2.warpPerspective()方法扭曲图像,如给定的代码片段所示。 ``` transformation_matrix = cv2.getPerspectiveTransform(pts1, pts2) ``` 变形的图像看起来像这样:  变形的图像 下一步是创建一个蒙版,我们为其创建一个具有基本图像形状的空白图像。 ``` mask = np.zeros(base_image.shape, dtype=np.uint8) ```  初始蒙版 在这个空白蒙版上,我们绘制一个具有由“ sorted\_pts ”指定的角的多边形,并使用cv2.fillConvexPoly()方法将其填充为白色,生成的蒙版将如下所示。 ``` roi_corners = np.int32(sorted_pts) ```  填充蒙版 现在我们使用cv2.bitwise\_not()方法反转蒙版颜色。 ``` mask = cv2.bitwise_not(mask) ```  倒置蒙版 现在我们使用cv2.bitwise\_and()方法获取蒙版和基础图像并执行按位与运算。 ``` masked_image = cv2.bitwise_and(base_image, mask) ``` 这将为我们提供如下所示的图像。我们可以看到单独放置对象图像的区域是黑色的。  蒙面基础图像 最后一步是使用cv2.bitwise\_or()方法获取变形图像和蒙版图像并执行按位或运算,这将生成我们想要完成的融合图像。 ``` output = cv2.bitwise_or(warped_img, masked_image) ``` 我们做到了!我们已经成功地将一张图片叠加到另一张图片上。  融合图像 这是透视变换的一个非常简单的用例。当我们跟踪框架中物体/人物的运动时,可以使用它来生成区域的鸟瞰图。 Github代码连接: https://github.com/GSNCodes/Image\_Overlaying\_Using\_Perspective\_Transform
-
图像二值化操作 两种方法,全局固定阈值二值化和局部自适应阈值二值化全局固定阈值很容易理解,就是对整幅图像都是用一个统一的阈值来进行二值化;局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值。效果:腐蚀操作滤波操作,模糊处理 模糊处理在边沿检测和去噪声方面有较为广泛的应用。OpenCV中提供了4种模糊算法,列举如下:averagemediangaussianbilateral这里我们只列举使用 均值滤波实现图像模糊:
-
【功能模块】在开发摄像头相关应用时,本人想采用opencv的imwrite()函数写图像数据到文件中,结果编译时提示报错。"/usr/local/ubuntu_crossbuild_devkit/sysroot//usr/lib/aarch64-linux-gnu/libpng16.so.16:对‘inflateValidate@ZLIB_1.2.9’未定义的引用"【操作步骤&问题现象】1、在mds工程中的CMakeList.txt里添加opencv相关的内容(增加了opencv库so与头文件的路径引用,以及so库名称的引用);2、代码中include opencv相关的头文件,并调用imwrite函数;3、编译提示报错。【截图信息】【日志信息】(可选,上传日志内容或者附件)LOG日志如附件“build_error_log.txt”所示。
-
Algodroid项目的主要任务是将CV系统集成到物联网解决方案中,以识别威胁生命的情况并为家中的老人提供安全。我们使用OpenCV实现计算机视觉,用于人体检测和骨骼可视化;并且我们建立了神经网络,并训练它们使用各种免费在线数据检测人类。为了分割人体骨骼,我们使用了基于TensorFlow的BodyPix。这是一个开源的ML模型,允许实时分割身体部位。该模型将人体分成24个部分,并将每个部分视为一组相同颜色的像素。分割身体后,我们的人体检测系统确定其生物力学数据,如身体几何和运动。这些参数通过OpenCV运动跟踪算法进行计算和分类。为了估计一个人的姿势,我们转向合成数据生成。通过使用仿真库,我们根据真实比例、生物特征和生物力学数据创建了人体的物理模型。我们将模型放置在虚拟环境中,并生成可能的人类行为场景。基于大约一百个场景,算法学会了估计姿态。我们建立了决策树,使估计的姿态与目标状态相匹配。这些算法将姿势与模拟场景和预测坠落的模式进行了比较。除此之外我们开发了一个通信系统,从安装在房子里的所有摄像机收集数据。在确认跌倒后,它可以发送照片并通知紧急医疗服务机构寻求进一步帮助。
-
OpenCV库在智能家庭中得到了广泛的应用,智能家庭是一种物联网系统,可以帮助人们运行智能家庭功能。物联网设备的网络可以控制灯光、调节室内温度、给植物浇水以及打开电视。提供安全是物联网家庭自动化的一个组成部分,因此,智能安全解决方案可以帮助家长照顾孩子。部署用于人员检测的计算机视觉应用程序可提高许多报警和视频对讲系统的安全性,实现OpenCV人脸识别可以防止陌生人进入房子或公寓。除了保护房屋不受入侵者的侵扰外,还必须确保独居者的安全,他们不能总是照顾自己。基于OpenCV算法和神经网络的计算机视觉人员检测系统可以远程监控老年人和有健康问题和残疾的人,在紧急情况下,他们可以提醒亲属或护理人员。在这里,我们将分享使用OpenCV构建用于实时人体检测的远程监控系统的个人经验。
-
OpenCV计算机视觉库概述 OpenCV是一组计算机视觉(CV)库,包含2500多个工具,从经典的机器学习(ML)算法到深度学习和神经网络。这是一个开源解三方库,可以在Apache许可下自由使用、修改和分发。该库与一系列操作系统兼容,包括Windows、Linux、macOS、FreeBSD、Android、iOS、BlackBerry 10,并支持用C/C++、Python和Java编写的软件。它具有强大的跨平台能力和与其他框架的兼容性。OpenCV包含一系列用于处理图像、检测和跟踪对象、描述特征以及执行许多其他任务的模块。该库配备了GPU模块,可提供高计算能力来实时捕获视频、处理图像和处理其他操作。OpenCV拥有一个庞大的全球社区,20多年来,数万名人工智能科学家、研究人员和工程师一直在为图书馆提供有价值的见解。
-
川剧是中国最知名的戏曲剧种之一,变脸是川剧表演的特技之一,在对象传承上有着严格的师门派别。有点扯远啦,回来!其实主要是我们今天要用OpenCV干的事情跟这个有点关系,OpenCV基于Landmark实现人脸关键点提取,对结果善加利用可以实现人脸交换,对特定对象施加变脸术。OpenCV开发者不学川剧也一样可以给各种人变脸,当然前提是会写代码,会做OpenCV。首先简单说一下原理与流程。一、原理与流程 基本原理是利用OpenCV的级联检测器实现人脸检测然后基于Landmak的LBF模型实现人脸68个关键点提取,基于关键点数据实现三角剖分与维诺图计算,经过几何变换之后得到mask区域,再利用OpenCV无缝克隆算法相关API实现换脸。整个工作流程如下:二、代码实现 1.创建Landmark关键点检测器// 人脸检测与Landmark68个关键点检测 CascadeClassifier face_cascade; face_cascade.load(cascade_name); FacemarkLBF::Params params; params.n_landmarks = 68; // 68个标注点 params.initShape_n = 10; params.stages_n = 5; // 算法的5个强化步骤 params.tree_n = 6; // 模型中每个标注点结构树 数目 params.tree_depth = 5; // 决策树深度 // 创建LBF landmark 检测器 Ptr<FacemarkLBF> facemark = FacemarkLBF::create(params); facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade); facemark->loadModel(modelfile_name); cout << "Loaded model" << endl;2.Landmark关键点检测//vector to store the faces detected in the image vector<Rect> faces1, faces2; vector< vector<Point2f> > shape1, shape2; //Detect faces in the current image float ratio1 = (float)img1.cols / (float)img1.rows; float ratio2 = (float)img2.cols / (float)img2.rows; resize(img1, img1, Size((int)(640 * ratio1), (int)(640 * ratio1)), 0, 0, INTER_LINEAR_EXACT); resize(img2, img2, Size((int)(640 * ratio2), (int)(640 * ratio2)), 0, 0, INTER_LINEAR_EXACT); Mat img1Warped = img2.clone(); facemark->getFaces(img1, faces1); facemark->getFaces(img2, faces2); //Initialise the shape of the faces facemark->fit(img1, faces1, shape1); facemark->fit(img2, faces2, shape2);3.三角剖分变换 vector<Po`int2f> points1 = shape1[z];` - `vector<Point2f> points2 = shape2[z];` - `img1.convertTo(img1, CV_32F);` - `img1Warped.convertTo(img1Warped, CV_32F);` - `// Find convex hull` - `vector<Point2f> boundary_image1;` - `vector<Point2f> boundary_image2;` - `vector<int> index;` - `convexHull(Mat(points2), index, false, false);` - `for (size_t i = 0; i < index.size(); i++)` - `{` - `boundary_image1.push_back(points1[index[i]]);` - `boundary_image2.push_back(points2[index[i]]);` - `}` - `// Triangulation for points on the convex hull` - `vector< vector<int> > triangles;` - `Rect rect(0, 0, img1Warped.cols, img1Warped.rows);` - `divideIntoTriangles(rect, boundary_image2, triangles);` - `// Apply affine transformation to Delaunay triangles` - `for (size_t i = 0; i < triangles.size(); i++)` - `{` - `vector<Point2f> triangle1, triangle2;` - `// Get points for img1, img2 corresponding to the triangles` - `for (int j = 0; j < 3; j++)` - `{` - `triangle1.push_back(boundary_image1[triangles[i][j]]);` - `triangle2.push_back(boundary_image2[triangles[i][j]]);` - `}` - `warpTriangle(img1, img1Warped, triangle1, triangle2);` - `}`4.计算与模板生成// 计算与生成模板` - `vector<Point> hull;` - `for (size_t i = 0; i < boundary_image2.size(); i++)` - `{` - `Point pt((int)boundary_image2[i].x, (int)boundary_image2[i].y);` - `hull.push_back(pt);` - `}` - `Mat mask = Mat::zeros(img2.rows, img2.cols, img2.depth());` - `fillConvexPoly(mask, &hull[0], (int)hull.size(), Scalar(255, 255, 255));`5.无缝克隆- `// 无缝克隆` - `Rect r = boundingRect(boundary_image2);` - `Point center = (r.tl() + r.br()) / 2;` - `Mat output;` - `img1Warped.convertTo(img1Warped, CV_8UC3);` - `seamlessClone(img1Warped, img2, mask, center, output, NORMAL_CLONE);` - `imshow("Face_Swapped", output);` - `imwrite("D:/face_swap_demo.png", output);`三、运行效果 原图一原图二人脸交换结果
-
一、介绍 照片中的面部分析引起了人们的广泛关注,因为它可以帮助我们解决各种问题,包括更好的客户广告定位、更好的内容推荐系统、安全监控和其他领域。年龄和性别是面部特征的重要方面,确定它们是此类活动的先决条件。许多企业出于各种原因使用这些技术,包括更轻松地与客户合作、更好地适应他们的需求以及提供良好的体验。人们的性别和年龄使得识别和预测他们的需求变得更加容易。即使对我们人类来说,从图像中检测性别和年龄也很困难,因为它完全基于外表,有时很难预测,同龄人的外表可能与我们预期的截然不同。应用 在监控计算机视觉中,经常使用年龄和性别预测。计算机视觉的进步使这一预测变得更加实用,更容易为公众所接受。由于其在智能现实世界应用中的实用性,该研究课题取得了重大进展。一个人的身份、年龄、性别、情绪和种族都是由他们脸上的特征决定的。年龄和性别分类是其中的两个特征,在各种实际应用中特别有用,包括安全和视频监控人机交互生物识别技术娱乐还有很多。实施 现在让我们学习如何使用 Python 中的 OpenCV 库通过相机或图片输入来确定年龄和性别。使用的框架是 Caffe,用于使用原型文件创建模型。让我们开始吧,如果我们还没有安装 OpenCV,请确保已经安装了它。pip install opencv-python numpy第 1 步:导入库 Import required modules import cv2 as cv import math import time from google.colab.patches import cv2_imshow第 2 步:在框架中查找边界框坐标使用下面的用户定义函数,我们可以获得边界框的坐标,也可以说人脸在图像中的位置。def getFaceBox(net, frame, conf_threshold=0.7): frameOpencvDnn = frame.copy() frameHeight = frameOpencvDnn.shape[0] frameWidth = frameOpencvDnn.shape[1] blob = cv.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False) net.setInput(blob) detections = net.forward() bboxes = [] for i in range(detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > conf_threshold: x1 = int(detections[0, 0, i, 3] * frameWidth) y1 = int(detections[0, 0, i, 4] * frameHeight) x2 = int(detections[0, 0, i, 5] * frameWidth) y2 = int(detections[0, 0, i, 6] * frameHeight) bboxes.append([x1, y1, x2, y2]) cv.rectangle(frameOpencvDnn, (x1, y1), (x2, y2), (0, 255, 0), int(round(frameHeight/150)), 8) return frameOpencvDnn, bboxes
推荐直播
-
华为云码道 × 仓颉编程:工程化AI编码探索2026/05/27 周三 19:00-21:00
刘俊杰-华为云仓颉语言专家/李炎-华为云码道技术专家/王智鹏-OpenCangjie开源社区发起人
本场直播围绕华为云仓颉语言与华为云码道的深度结合,展示华为云智能编程从零基础到高效落地的完整生态能力。以华为云码道为引擎,仓颉语言为载体,带给大家日常提效、趣味创新到极速量产的开发体验。
回顾中
热门标签