-
计算机视觉是最令人兴奋的领域之一,其应用范围非常广泛。从医学成像到创建最有趣的面部滤镜等各个领域都充分见证了计算机视觉技术的强大。在本文中,我们将尝试创建一个人造眼线笔来模仿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度,然后您必须执行第二遍,修改内核的方向。• 它只能在固定尺寸范围内找到条形码。• 尽管对矩形区域施加了过滤,但仍有可能无法清除某些非条形码。第一个和第二个可能不是真正的问题,但是最后一个可能会花费大家大量时间来尝试解码非条形码的内容。一个很好的解决方案是将条形码特征(图像梯度,傅立叶变换)输入给神经网络(或一些其他一些分类器),并在第二时刻过滤掉噪声。
-
【功能模块】rtsp流解码【操作步骤&问题现象】在Atlas300上,已跑通C++版YOLOV3_coco_detection_video实例,但使用Opnecv读取海康摄像头的rtsp流时,延迟严重,并会报“[hevc @ 0x2ffcaba0] Could not find ref with POC 7”,有什么解决办法呢?
-
小伙伴们可能会觉得从图像中提取文本是一件很麻烦的事情,尤其是需要提取大量文本时。PyTesseract是一种光学字符识别(OCR),该库提了供文本图像。PyTesseract确实有一定的效果,用PyTesseract来检测短文本时,结果相当不错。但是,当我们用它来检测表格中的文本时,算法执行失败。图1.直接使用PyTesseract检测表中的文本图1描绘了文本检测结果,绿色框包围了检测到的单词。可以看出算法对于大部分文本都无法检测,尤其是数字。而这些数字却是展示了每日COVID-19病例的相关信息。那么,如何提取这些信息?简介 在编写算法时,我们通常应该以我们人类理解问题的方式来编写算法。这样,我们可以轻松地将想法转化为算法。当我们阅读表格时,首先注意到的就是单元格。一个单元格使用边框(线)与另一个单元格分开,边框可以是垂直的也可以是水平的。识别单元格后,我们继续阅读其中的信息。将其转换为算法,您可以将过程分为三个过程,即单元格检测、区域(ROI)选择和文本提取。在执行每个任务之前,让我们先导入必要内容import cv2 as cv import numpy as np filename = 'filename.png' img = cv.imread(cv.samples.findFile(filename)) cImage = np.copy(img) #image to draw lines cv.imshow("image", img) #name the window as "image" cv.waitKey(0) cv.destroyWindow("image") #close the window单元格检测 查找表格中的水平线和垂直线可能是最容易开始的。有多种检测线的方法,这里我们采用OpenCV库中的Hough Line Transform。在应用霍夫线变换之前,需要进行一些预处理。第一是将存在的RGB图像转换为灰度图像。因为灰度图像对于Canny边缘检测而言非常重要。gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) cv.imshow("gray", gray) cv.waitKey(0) cv.destroyWindow("gray") canny = cv.Canny(gray, 50, 150) cv.imshow("canny", canny) cv.waitKey(0) cv.destroyWindow("canny")下面的两幅图分别显示了灰度图像和Canny图像。图2.灰度和Canny图像霍夫线变换 在OpenCV中,此算法有两种类型,即标准霍夫线变换和概率霍夫线变换。标准变换为我们提供直线方程,因此我们无法得知直线的起点和终点。概率变换将为我们提供线列表,即直线起点与终点的坐标值列表。我们优先选用的是概率变化。图3.霍夫线变换结果示例(来源:OpenCV)对于HoughLinesP函数,有如下几个输入参数:image -8位单通道二进制源图像。该图像可以通过该功能进行修改。rho —累加器的距离分辨率,以像素为单位。theta —弧度的累加器角度分辨率。threshold-累加器阈值参数。仅返回那些获得足够投票的行line — 线的输出向量。这里设置为无,该值保存到linesPminLineLength —最小行长。短于此的线段将被拒绝。maxLineGap —同一线上的点之间允许链接的最大间隙。# cv.HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) → lines rho = 1 theta = np.pi/180 threshold = 50 minLinLength = 350 maxLineGap = 6 linesP = cv.HoughLinesP(canny, rho , theta, threshold, None, minLinLength, maxLineGap)为了区分水平线和垂直线,我们定义了一个函数并根据该函数的返回值添加列表。def is_vertical(line): return line[0]==line[2] def is_horizontal(line): return line[1]==line[3] horizontal_lines = [] vertical_lines = [] if linesP is not None: for i in range(0, len(linesP)): l = linesP[i][0] if (is_vertical(l)): vertical_lines.append(l) elif (is_horizontal(l)): horizontal_lines.append(l) for i, line in enumerate(horizontal_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,255,0), 3, cv.LINE_AA) for i, line in enumerate(vertical_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,0,255), 3, cv.LINE_AA) cv.imshow("with_line", cImage) cv.waitKey(0) cv.destroyWindow("with_line") #close the window图4.霍夫线变换结果—没有重叠滤波器重叠滤波器 检测到的线如上图所示。但是,霍夫线变换结果中有一些重叠的线。较粗的线由多个相同位置,长度不同的线组成。为了消除此重叠线,我们定义了一个重叠过滤器。最初,基于分类索引对线进行分类,水平线的y₁和垂直线的x₁。如果下一行的间隔小于一定距离,则将其视为与上一行相同的行。def overlapping_filter(lines, sorting_index): filtered_lines = [] lines = sorted(lines, key=lambda lines: lines[sorting_index]) separation = 5 for i in range(len(lines)): l_curr = lines[i] if(i>0): l_prev = lines[i-1] if ( (l_curr[sorting_index] - l_prev[sorting_index]) > separation): filtered_lines.append(l_curr) else: filtered_lines.append(l_curr) return filtered_lines实现重叠滤镜并在图像上添加文本,现在代码应如下所示:horizontal_lines = [] vertical_lines = [] if linesP is not None: for i in range(0, len(linesP)): l = linesP[i][0] if (is_vertical(l)): vertical_lines.append(l) elif (is_horizontal(l)): horizontal_lines.append(l) horizontal_lines = overlapping_filter(horizontal_lines, 1) vertical_lines = overlapping_filter(vertical_lines, 0) for i, line in enumerate(horizontal_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,255,0), 3, cv.LINE_AA) cv.putText(cImage, str(i) + "h", (line[0] + 5, line[1]), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA) for i, line in enumerate(vertical_lines): cv.line(cImage, (line[0], line[1]), (line[2], line[3]), (0,0,255), 3, cv.LINE_AA) cv.putText(cImage, str(i) + "v", (line[0], line[1] + 5), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv.LINE_AA) cv.imshow("with_line", cImage) cv.waitKey(0) cv.destroyWindow("with_line") #close the window图5.霍夫线变换结果—带重叠滤波器有了这个代码,就不会提取出重叠的行了。此外,我们还将在图像中写入水平和垂直线的索引,这将有利于ROI的选择。ROI选择 首先,我们需要定义列数和行数。这里我们只对第二行第十四行以及所有列中的数据感兴趣。对于列,我们定义了一个名为关键字的列表,将其用于字典关键字。## set keywords keywords = ['no', 'kabupaten', 'kb_otg', 'kl_otg', 'sm_otg', 'ks_otg', 'not_cvd_otg', 'kb_odp', 'kl_odp', 'sm_odp', 'ks_odp', 'not_cvd_odp', 'death_odp', 'kb_pdp', 'kl_pdp', 'sm_pdp', 'ks_pdp', 'not_cvd_pdp', 'death_pdp', 'positif', 'sembuh', 'meninggal'] dict_kabupaten = {} for keyword in keywords: dict_kabupaten[keyword] = [] ## set counter for image indexing counter = 0 ## set line index first_line_index = 1 last_line_index = 14然后,要选择ROI,我们定义了一个函数,该函数将图像(水平线和垂直线都作为输入)以及线索引作为边框。此函数返回裁剪的图像及其在图像全局坐标中的位置和大小def get_cropped_image(image, x, y, w, h): cropped_image = image[ y:y+h , x:x+w ] return cropped_image def get_ROI(image, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index, offset=4): x1 = vertical[left_line_index][2] + offset y1 = horizontal[top_line_index][3] + offset x2 = vertical[right_line_index][2] - offset y2 = horizontal[bottom_line_index][3] - offset w = x2 - x1 h = y2 - y1 cropped_image = get_cropped_image(image, x1, y1, w, h) return cropped_image, (x1, y1, w, h)裁剪的图像将用于下一个任务,即文本提取。返回的第二个参数将用于绘制ROI的边界框文字提取 现在,我们定义了ROI功能。我们可以继续提取结果。我们可以通过遍历单元格来读取列中的所有数据。列数由关键字的长度指定,而行数则由定义。首先,让我们定义一个函数来绘制文本和周围的框,并定义另一个函数来提取文本。import pytesseract pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe' def draw_text(src, x, y, w, h, text): cFrame = np.copy(src) cv.rectangle(cFrame, (x, y), (x+w, y+h), (255, 0, 0), 2) cv.putText(cFrame, "text: " + text, (50, 50), cv.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 0), 5, cv.LINE_AA) return cFrame def detect(cropped_frame, is_number = False): if (is_number): text = pytesseract.image_to_string(cropped_frame, config ='-c tessedit_char_whitelist=0123456789 --psm 10 --oem 2') else: text = pytesseract.image_to_string(cropped_frame, config='--psm 10') return text将图像转换为黑白以获得更好的效果,让我们开始迭代!counter = 0 print("Start detecting text...") (thresh, bw) = cv.threshold(gray, 100, 255, cv.THRESH_BINARY) for i in range(first_line_index, last_line_index): for j, keyword in enumerate(keywords): counter += 1 left_line_index = j right_line_index = j+1 top_line_index = i bottom_line_index = i+1 cropped_image, (x,y,w,h) = get_ROI(bw, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index) if (keywords[j]=='kabupaten'): text = detect(cropped_image) dict_kabupaten[keyword].append(text) else: text = detect(cropped_image, is_number=True) dict_kabupaten[keyword].append(text) image_with_text = draw_text(img, x, y, w, h, text)问题解决 这是文本提取的结果!我们只选择了最后三列,因为它对某些文本给出了奇怪的结果,其余的很好,所以我不显示它。图6.检测到的文本—版本1一些数字被检测为随机文本,即39个数据中的5个。这是由于最后三列与其余列不同。文本为白色时背景为黑色,会以某种方式影响文本提取的性能。图7.二进制图像为了解决这个问题,让我们倒数最后三列。def invert_area(image, x, y, w, h, display=False): ones = np.copy(image) ones = 1 image[ y:y+h , x:x+w ] = ones*255 - image[ y:y+h , x:x+w ] if (display): cv.imshow("inverted", image) cv.waitKey(0) cv.destroyAllWindows() return image left_line_index = 17 right_line_index = 20 top_line_index = 0 bottom_line_index = -1 cropped_image, (x, y, w, h) = get_ROI(img, horizontal, vertical, left_line_index, right_line_index, top_line_index, bottom_line_index) gray = get_grayscale(img) bw = get_binary(gray) bw = invert_area(bw, x, y, w, h, display=True)结果如下所示。结果 反转图像后,重新执行步骤,这是最终结果!算法成功检测到文本后,现在可以将其保存到Python对象(例如Dictionary或List)中。由于Tesseract训练数据中未包含某些地区名称(“ Kabupaten / Kota”中的名称),因此无法准确检测到。但是,由于可以精确检测到地区的索引,因此这不会成为问题。文本提取可能无法检测到其他字体的文本,具体取决于所使用的字体,如果出现误解,例如将“ 5”检测为“ 8”,则可以进行诸如腐蚀膨胀之类的图像处理。源代码:https://github.com/fazlurnu/Text-Extraction-Table-Image本文转自小白学视觉公众号
-
计算机视觉现在很流行,世界各地的人们都在从事某种形式的基于深度学习的计算机视觉项目。但在深度学习出现之前,图像处理技术已被用来处理和转换图像,以获得有助于我们完成任务的见解。今天,让我们看看如何实现一种简单而有用的技术,即透视投影来扭曲图像。 那么扭曲图像是什么意思?我可以用很多花哨的词和技术术语来解释它。但是,展示最终结果很容易,这样我们就可以通过观察来学习。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/211932dwqd6zlfqi5kw9hf.png) 基础图像——主题图像——扭曲的输出 所以基本上,我们需要拍摄一个图像并剪切它以使其适合任何所需形状的画布。请注意,反过来也是可能的。现在,这已经不成问题了,让我们就来看看如何使用 OpenCV 和 Python 来实现这一点。 在进入代码的主要部分之前,我们必须首先导入必要的库。 ``` import cv2 ``` 现在,让我们按如下方式读取基本图像和主题图像。 ``` base_image = cv2.imread('base_img.jpg') ``` ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/211953qxlkohcod1mwzrtu.png) 基本图像(左)——主体图像(右) 初始化一个数组来存储我们想要覆盖主题图像的 4 个角的坐标,我们可以使用setMouseCallback()函数手动选择这 4 个点,如下所示。 ``` def click_event(event, x, y, flags, params): ``` 在上面给出的代码片段中,我们定义了一个名为click\_event()的函数,并将其作为参数传递给setMouseCallback()函数。使用这种方法,我们将首先显示基础图像,然后我们可以手动选择图像中的四个点作为目标。我们的主题图像会扭曲到这个目标上,按下鼠标左键时记录坐标,这些存储在我们之前初始化的点数组中。选定的点以红点突出显示,如下所示。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212032ahgktj3xf323g2it.png) 选择角点 众所周知,我们每个人都可以按任意顺序选择 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) ``` 变形的图像看起来像这样: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212103qxagsz6x34yi5mhf.png) 变形的图像 下一步是创建一个蒙版,我们为其创建一个具有基本图像形状的空白图像。 ``` mask = np.zeros(base_image.shape, dtype=np.uint8) ``` ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212118xeixq4mctvf2lxi1.png) 初始蒙版 在这个空白蒙版上,我们绘制一个具有由“ sorted\_pts ”指定的角的多边形,并使用cv2.fillConvexPoly()方法将其填充为白色,生成的蒙版将如下所示。 ``` roi_corners = np.int32(sorted_pts) ``` ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/21212877bxqmpv7le3tayb.png) 填充蒙版 现在我们使用cv2.bitwise\_not()方法反转蒙版颜色。 ``` mask = cv2.bitwise_not(mask) ``` ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212156rh62ujui9knmjkfu.png) 倒置蒙版 现在我们使用cv2.bitwise\_and()方法获取蒙版和基础图像并执行按位与运算。 ``` masked_image = cv2.bitwise_and(base_image, mask) ``` 这将为我们提供如下所示的图像。我们可以看到单独放置对象图像的区域是黑色的。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212209wqjqxxy4jrxix46j.png) 蒙面基础图像 最后一步是使用cv2.bitwise\_or()方法获取变形图像和蒙版图像并执行按位或运算,这将生成我们想要完成的融合图像。 ``` output = cv2.bitwise_or(warped_img, masked_image) ``` 我们做到了!我们已经成功地将一张图片叠加到另一张图片上。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/21/212225cii00o8nioclbwiw.png) 融合图像 这是透视变换的一个非常简单的用例。当我们跟踪框架中物体/人物的运动时,可以使用它来生成区域的鸟瞰图。 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
-
OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用,并在可用时利用MMX和SSE指令, 如今也提供对于C#、Ch、Ruby,GO的支持如今的计算机视觉软件大概有以下三种:1、研究代码(慢,不稳定,独立并与其他库不兼容)2、耗费很高的商业化工具(比如Halcon, MATLAB+Simulink)3、依赖硬件的一些特别的解决方案(比如视频监控,制造控制系统,医疗设备)这是如今的现状,而标准的API将简化计算机视觉程序和解决方案的开发,OpenCV致力于成为这样的标准API。OpenCV致力于真实世界的实时应用,通过优化的C代码的编写对其执行速度带来了可观的提升,并且可以通过购买Intel的IPP高性能多媒体函数库(Integrated Performance Primitives)得到更快的处理速度。应用领域1、人机互动2、物体识别3、图像分割4、人脸识别5、动作识别6、运动跟踪7、机器人8、运动分析9、机器视觉10、结构分析11、汽车安全驾驶
-
OpenCV是一个非常强大的计算机视觉处理的工具库。在入门图像处理时都需要学习OpenCV的使用。但是随着计算机视觉技术的发展,越来越多的算法涌现出来,人们逐渐觉得OpenCV比较落后而放弃了使用OpenCV。但是,实际上OpenCV时一个与时俱进的开源代码库。正在逐渐的吸收和接纳最新的算法。本文我们来介绍如何使用OpenCV实现基于深度学习的图像超分辨率(SR)。使用OpenCV的好处就是,我们不需要知道任何图像超分辨率的相关知识,就可以使用这个代码,并实现图像超分辨率。具体操作步骤 1. 安装OpenCV contrib模块OpenCV中的超分辨率功能被集成在了contrib模块中,因此我们首先需要安装OpenCV的扩展模块。2. 下载训练的模型由于某些模型比较大,因此OpenCV代码库中没有包含他们,因此我们在使用的时候需要单独的下载经过训练的模型。目前,仅支持4种不同的超分辨率模型,他们可以实现2倍、3倍、4倍甚至8倍的图像方法。这些模型具体如下:EDSR:这个是表现最好的模型。但是这个模型也是最大的,所以运行速度会比较慢。 ESPCN:这个模型具有速度快,效果好的特点,并且模型较小。它可以进行对视频进行实时处理(取决于图像大小)。 FSRCNN:这也是具有快速准确推断功能的小型模型。也可以进行实时视频升频。 LapSRN:这是一个中等大小的模型,它的特点是最大可以将图像放大8倍。 3. 通过程序实现超分辨率 C++实现超分辨率的代码 #include <opencv2/dnn_superres.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> using namespace std; using namespace cv; using namespace dnn; using namespace dnn_superres; int main(int argc, char *argv[]) { //Create the module's object DnnSuperResImpl sr; //Set the image you would like to upscale string img_path = "image.png"; Mat img = cv::imread(img_path); //Read the desired model string path = "FSRCNN_x2.pb"; sr.readModel(path); //Set the desired model and scale to get correct pre- and post-processing sr.setModel("fsrcnn", 2); //Upscale Mat img_new; sr.upsample(img, img_new); cv::imwrite( "upscaled.png", img_new); return 0; }首先加载我们选择的模型,并将其输入到神经网络的变量中。需要注意的是模型文件所存在的地址,本文放置在了程序的根目录中。//Read the desired model string path = "FSRCNN_x2.pb"; sr.readModel(path);之后设置模型的种类和放大系数。本文选择的模型是fsrcnn,放大系数选择的2。//Set the desired model and scale to get correct pre- and post-processing sr.setModel("fsrcnn", 2);可以选择的模型有“ edsr”,“ fsrcnn”,“ lapsrn”,“ espcn”,这几个参数就是我们刚才介绍的4中模型。需要注意的是,每个模型能够放大的倍数是不一致的。前三种模型能够放大2、3、4倍,最后一个模型能够放大2、3、4、8倍。 之后通过upsample()函数进行超分辨率放大。 //Upscale Mat img_new; sr.upsample(img, img_new); cv::imwrite( "upscaled.png", img_new);Python实现超分辨率的代码import cv2 from cv2 import dnn_superres # Create an SR object sr = dnn_superres.DnnSuperResImpl_create() # Read image image = cv2.imread('./input.png') # Read the desired model path = "EDSR_x3.pb" sr.readModel(path) # Set the desired model and scale to get correct pre- and post-processing sr.setModel("edsr", 3) # Upscale the image result = sr.upsample(image) # Save the image cv2.imwrite("./upscaled.png", result)不同于C++代码,在使用python代码时,需要先通过如下代码进行声明。# Create an SR object sr = dnn_superres.DnnSuperResImpl_create()4. 处理结果
上滑加载中
推荐直播
-
GaussDB管理平台TPOPS,DBA高效运维的一站式解决方案
2024/12/24 周二 16:30-18:00
Leo 华为云数据库DTSE技术布道师
数据库的复杂运维,是否让你感到头疼不已?今天,华为云GaussDB管理平台将彻底来改观!本期直播,我们将深入探索GaussDB管理平台的TPOPS功能,带你感受一键式部署安装的便捷,和智能化运维管理的高效,让复杂的运维、管理变得简单,让简单变得可靠。
回顾中 -
DTT年度收官盛典:华为开发者空间大咖汇,共探云端开发创新
2025/01/08 周三 16:30-18:00
Yawei 华为云开发工具和效率首席专家 Edwin 华为开发者空间产品总监
数字化转型进程持续加速,驱动着技术革新发展,华为开发者空间如何巧妙整合鸿蒙、昇腾、鲲鹏等核心资源,打破平台间的壁垒,实现跨平台协同?在科技迅猛发展的今天,开发者们如何迅速把握机遇,实现高效、创新的技术突破?DTT 年度收官盛典,将与大家共同探索华为开发者空间的创新奥秘。
回顾中
热门标签