介绍
在本教程中,您将学习:
- 如何将现有算法转换为 G-API 计算(图);
- 如何检查和分析 G-API 图形;
- 如何在不更改其代码的情况下自定义图形执行。
本教程基于梯度结构张量的各向异性图像分割。
快速入门:使用 OpenCV 后端
在开始之前,我们先回顾一下原始的算法实现:
#include < iostream>#include“opencv2/highgui.hpp”#include“opencv2/imgproc.hpp”#include“opencv2/imgcodecs.hpp”使用命名空间 CV;使用命名空间 std;void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w);int main(){intW = 52;窗口大小为 WxW双C_Thr = 0.43;// 一致性阈值intLowThr = 35;threshold1 用于方向,范围为 0 到 180intHighThr = 57;// threshold2 表示方向,范围为 0 到 180示例::addSamplesDataSearchSubDirectory(“doc/tutorials/imgproc/anisotropic_image_segmentation/images”);垫子 imgIn = imread(samples::findFile(“gst_input.jpg”), IMREAD_GRAYSCALE);如果 (imgIn.empty()) //检查图片是否加载成功{cout << “错误:无法加载图像..!!” << endl;返回 -1;}垫子 imgCoherency, imgOrientation;calcGST(imgIn, imgCoherency, imgOrientation, W);垫子 imgCoherencyBin;imgCoherencyBin = imgCoherency > C_Thr;垫子 imgOrientationBin;inRange(imgOrientation, Scalar(LowThr), Scalar(HighThr), imgOrientationBin);垫子imgBin;imgBin = imgCoherencyBin & imgOrientationBin;归一化(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX, CV_8U);normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX, CV_8U);imshow(“原始”, imgIn);imshow(“结果”, 0.5 * (imgIn + imgBin));imshow(“连贯性”, img连贯性);imshow(“方向”, imgOrientation);imwrite(“结果.jpg”, 0.5*(imgIn + imgBin));imwrite(“一致性.jpg”, img一致性);imwrite(“方向.jpg”, imgOrientation);waitKey(0);返回 0;}void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w){
输入Img。convertTo(img, CV_32F);GST组成部分计算(开始)J = (J11 J12;J12 J22) - 消费税垫子 imgDiffX、imgDiffY、imgDiffXY;索贝尔(img, imgDiffX, CV_32F, 1, 0, 3);索贝尔(img, imgDiffY, CV_32F, 0, 1, 3);乘(imgDiffX, imgDiffY, imgDiffXY);垫子 imgDiffXX, imgDiffYY;乘(imgDiffX, imgDiffX, imgDiffXX);乘(imgDiffY, imgDiffY, imgDiffYY);席J11、J22、J12;J11、J22 和 J12 是 GST 组件boxFilter(imgDiffXX, J11, CV_32F, Size(w, w));boxFilter(imgDiffYY, J22, CV_32F, Size(w, w));boxFilter(imgDiffXY, J12, CV_32F, Size(w, w));GST组成部分计算(停止)特征值计算(开始)lambda1 = 0.5*(J11 + J22 + sqrt((J11-J22)^2 + 4*J12^2))lambda2 = 0.5*(J11 + J22 - sqrt((J11-J22)^2 + 4*J12^2))垫子 tmp1、tmp2、tmp3、tmp4;tmp1 = J11 + J22;tmp2 = J11 - J22;乘(tmp2, tmp2, tmp2);乘(J12, J12, tmp3);sqrt(tmp2 + 4.0 * tmp3, tmp4);垫子 lambda1, lambda2;lambda1 = tmp1 + tmp4;lambda1 = 0.5*lambda1;最大特征值 // 最大特征值lambda2 = tmp1 - tmp4;lambda2 = 0.5*lambda2;最小特征值 //特征值计算(停止)相干性计算(开始)相干性 = (lambda1 - lambda2)/(lambda1 + lambda2)) - 各向异性的量度相干性是各向异性程度(局部方向的一致性)divide(lambda1 - lambda2, lambda1 + lambda2, imgCoherencyOut);相干性计算(停止)方向角计算(开始)tan(2*阿尔法) = 2*J12/(J22 - J11)阿尔法 = 0.5 atan2(2*J12/(J22 - J11))phase(J22 - J11, 2.0*J12, imgOrientationOut, true);imgOrientationOut = 0.5*imgOrientationOut;方向角计算(停止)}
检查 calcGST()
函数 calcGST() 显然是一个图像处理管道:
- 它只是对多个 cv::Mat 的一系列操作;
- 代码中不涉及逻辑(条件)和循环;
- 所有函数都对 2D 图像进行操作(如 cv::Sobel、cv::multiply、cv::boxFilter、cv::sqrt 等)。
考虑到上述情况,calcGST() 是一个很好的候选者。在原始代码中,它的原型是这样定义的:
使用 G-API,我们可以将其定义如下:
重要的是要了解,基于 G-API 的 calcGST() 的新版本只会生成一个计算图,而其原始版本实际上会计算值。这是一个主要区别——像这样的基于 G-API 的函数用于构建图形,而不是处理实际数据。
让我们开始通过计算 让我们开始通过矩阵计算来实现 calcGST()。原始代码如下所示: 矩阵来实现 calcGST()。原始代码如下所示:J
void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w){垫子img;输入Img。convertTo(img, CV_32F);GST组成部分计算(开始)J = (J11 J12;J12 J22) - 消费税垫子 imgDiffX、imgDiffY、imgDiffXY;索贝尔(img, imgDiffX, CV_32F, 1, 0, 3);索贝尔(img, imgDiffY, CV_32F, 0, 1, 3);乘(imgDiffX, imgDiffY, imgDiffXY);在这里,我们需要为每个新操作声明输出对象(参见 img 作为 cv::Mat::convertTo 的结果,imgDiffX 和其他作为 cv::Sobel 和 cv::multiply 的结果)。
下面列出了 G-API 类似物:
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w){自动 img = cv::gapi::convertTo(inputImg, CV_32F);自动 imgDiffX = cv::gapi::Sobel(img, CV_32F, 1, 0, 3);自动 imgDiffY = cv::gapi::Sobel(img, CV_32F, 0, 1, 3);自动 imgDiffXY = cv::gapi::mul(imgDiffX, imgDiffY);
此代码片段演示了 G-API 与传统 OpenCV 之间的以下语法差异:
- 默认情况下,所有标准 G-API 函数都放置在 “cv::gapi” 命名空间中;
- G-API 操作返回其结果 - 无需将额外的“输出”参数传递给函数。
注意 – 此代码还使用 – 中间对象的类型,如 、 等由 C++ 编译器自动推断。在此示例中,类型由 G-API 操作返回值确定,这些返回值均为 cv::GMat。auto
img
imgDiffX
G-API 标准内核尽可能遵循 OpenCV API 约定——因此 cv::gapi::sobel 采用与 cv::Sobel 相同的参数,cv::gapi::mul 遵循 cv::multiply,依此类推(除了具有返回值)。
calcGST() 函数的其余部分可以以相同的方式轻松实现。以下是其完整的源代码:
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w){自动 img = cv::gapi::convertTo(inputImg, CV_32F);自动 imgDiffX = cv::gapi::Sobel(img, CV_32F, 1, 0, 3);自动 imgDiffY = cv::gapi::Sobel(img, CV_32F, 0, 1, 3);自动 imgDiffXY = cv::gapi::mul(imgDiffX, imgDiffY);自动 imgDiffXX = cv::gapi::mul(imgDiffX, imgDiffX);自动 imgDiffYY = cv::gapi::mul(imgDiffY, imgDiffY);自动J11 = cv::gapi::boxFilter(imgDiffXX, CV_32F, cv::Size(w, w));自动J22 = cv::gapi::boxFilter(imgDiffYY, CV_32F, cv::Size(w, w));自动J12 = cv::gapi::boxFilter(imgDiffXY, CV_32F, cv::Size(w, w));自动 tmp1 = J11 + J22;自动 tmp2 = J11 - J22;自动 tmp22 = cv::gapi::mul(tmp2, tmp2);自动 tmp3 = cv::gapi::mul(J12, J12);自动 tmp4 = cv::gapi::sqrt(tmp22 + 4.0*tmp3);自动 lambda1 = tmp1 + tmp4;自动 lambda2 = tmp1 - tmp4;imgCoherencyOut = (lambda1 - lambda2) / (lambda1 + lambda2);imgOrientationOut = 0.5*cv::gapi::p hase(J22 - J11, 2.0*J12, true);}
运行 G-API 图形
在 G-API 语言中定义 calcGST() 后,我们可以基于它构建一个图,并最终运行它——传递输入图像并得到结果。在我们这样做之前,让我们看一下原始代码的样子:
垫子 imgCoherency, imgOrientation;calcGST(imgIn, imgCoherency, imgOrientation, W);垫子 imgCoherencyBin;imgCoherencyBin = imgCoherency > C_Thr;垫子 imgOrientationBin;inRange(imgOrientation, Scalar(LowThr), Scalar(HighThr), imgOrientationBin);垫子imgBin;imgBin = imgCoherencyBin & imgOrientationBin;归一化(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX, CV_8U);normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX, CV_8U);imshow(“原始”, imgIn);imshow(“结果”, 0.5 * (imgIn + imgBin));imshow(“连贯性”, img连贯性);imshow(“方向”, imgOrientation);imwrite(“结果.jpg”, 0.5*(imgIn + imgBin));imwrite(“一致性.jpg”, img一致性);imwrite(“方向.jpg”, imgOrientation);waitKey(0);
基于 G-API 的函数(如 calcGST())不能直接应用于输入数据,因为它是构造代码,而不是处理代码。为了运行计算,需要创建一个类为 cv::GComputation 的特殊对象。此对象将我们的 G-API 代码(G-API 数据和操作的组合)包装到一个可调用的对象中,类似于 C++11 std::function<>。
cv::GComputation 类有许多构造函数,可用于定义图形。通常,用户需要传递图形边界 - 输入和输出对象,在其上定义了 GComputation。然后,G-API 分析从输出到输入的调用流,并在指定边界之间使用操作重建图形。这听起来可能很复杂,但实际上代码如下所示:
计算梯度结构张量,并使用 G-API 对其进行后处理以输出cv::GMat 输入;cv::GMat imgCoherency, imgOrientation;calcGST(in, imgCoherency, imgOrientation, W);cv::GMat imgCoherencyBin = imgCoherency > C_Thr;cv::GMat imgOrientationBin = cv::gapi::inRange(imgOrientation, LowThr, HighThr);cv::GMat imgBin = imgCoherencyBin & imgOrientationBin;cv::GMat out = cv::gapi::addWeighted(in, 0.5, imgBin, 0.5, 0.0);规范化额外输出cv::GMat imgCoherencyNorm = cv::gapi::normalize(imgCoherency, 0, 255, cv::NORM_MINMAX );cv::GMat imgOrientationNorm = cv::gapi::normalize(imgOrientation, 0, 255, cv::NORM_MINMAX );将图形捕获到对象段中cv::GComputation segm(cv::GIn(in), cv::GOut(out, imgCoherencyNorm, imgOrientationNorm));定义输出数据的 cv::Matscv::Mat imgOut、imgOutCoherency、imgOutOrientation;运行图形segm.apply(cv::gin(imgIn), cv::gout(imgOut, imgOutCoherency, imgOutOrientation));cv::imwrite(“结果.jpg”, imgOut);cv::imwrite(“一致性.jpg”, imgOut一致性);cv::imwrite(“方向.jpg”, imgOutOrientation);
请注意,此代码与原始代码略有不同:形成生成的图像也是管道的一部分(使用 cv::gapi::addWeighed 完成)。
此 G-API 管道的结果与原始结果完全匹配(给定相同的输入图像):
G-API初始版本:完整列表
以下是 G-API 上初始各向异性图像分割端口的完整列表:
#include < iostream>#include < 效用>#include“opencv2/imgproc.hpp”#include“opencv2/imgcodecs.hpp”#include“opencv2/gapi.hpp”#include “opencv2/gapi/core.hpp”#include“opencv2/gapi/imgproc.hpp”void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w);int main(){intW = 52;窗口大小为 WxW双C_Thr = 0.43;// 一致性阈值intLowThr = 35;threshold1 用于方向,范围为 0 到 180intHighThr = 57;// threshold2 表示方向,范围为 0 到 180cv::Mat imgIn = cv::imread(“输入.jpg”, cv::IMREAD_GRAYSCALE );如果 (imgIn.empty()) //检查图片是否加载成功{std::cout << “错误:无法加载图像..!!” << std::endl;返回 -1;}
返回 0;}void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w){自动 img = cv::gapi::convertTo(inputImg, CV_32F);自动 imgDiffX = cv::gapi::Sobel(img, CV_32F, 1, 0, 3);自动 imgDiffY = cv::gapi::Sobel(img, CV_32F, 0, 1, 3);自动 imgDiffXY = cv::gapi::mul(imgDiffX, imgDiffY);自动 imgDiffXX = cv::gapi::mul(imgDiffX, imgDiffX);自动 imgDiffYY = cv::gapi::mul(imgDiffY, imgDiffY);自动J11 = cv::gapi::boxFilter(imgDiffXX, CV_32F, cv::Size(w, w));自动J22 = cv::gapi::boxFilter(imgDiffYY, CV_32F, cv::Size(w, w));自动J12 = cv::gapi::boxFilter(imgDiffXY, CV_32F, cv::Size(w, w));自动 tmp1 = J11 + J22;自动 tmp2 = J11 - J22;自动 tmp22 = cv::gapi::mul(tmp2, tmp2);自动 tmp3 = cv::gapi::mul(J12, J12);自动 tmp4 = cv::gapi::sqrt(tmp22 + 4.0*tmp3);自动 lambda1 = tmp1 + tmp4;自动 lambda2 = tmp1 - tmp4;imgCoherencyOut = (lambda1 - lambda2) / (lambda1 + lambda2);imgOrientationOut = 0.5*cv::gapi::p hase(J22 - J11, 2.0*J12, true);}
在线教程
- 麻省理工学院人工智能视频教程 – 麻省理工人工智能课程
- 人工智能入门 – 人工智能基础学习。Peter Norvig举办的课程
- EdX 人工智能 – 此课程讲授人工智能计算机系统设计的基本概念和技术。
- 人工智能中的计划 – 计划是人工智能系统的基础部分之一。在这个课程中,你将会学习到让机器人执行一系列动作所需要的基本算法。
- 机器人人工智能 – 这个课程将会教授你实现人工智能的基本方法,包括:概率推算,计划和搜索,本地化,跟踪和控制,全部都是围绕有关机器人设计。
- 机器学习 – 有指导和无指导情况下的基本机器学习算法
- 机器学习中的神经网络 – 智能神经网络上的算法和实践经验
- 斯坦福统计学习
有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
人工智能书籍
- OpenCV(中文版).(布拉德斯基等)
- OpenCV+3计算机视觉++Python语言实现+第二版
- OpenCV3编程入门 毛星云编著
- 数字图像处理_第三版
- 人工智能:一种现代的方法
- 深度学习面试宝典
- 深度学习之PyTorch物体检测实战
- 吴恩达DeepLearning.ai中文版笔记
- 计算机视觉中的多视图几何
- PyTorch-官方推荐教程-英文版
- 《神经网络与深度学习》(邱锡鹏-20191121)
- …
第一阶段:零基础入门(3-6个月)
新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。
第二阶段:基础进阶(3-6个月)
熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。
第三阶段:工作应用
这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。
有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
文章来源:https://www.toymoban.com/news/detail-836762.html
文章来源地址https://www.toymoban.com/news/detail-836762.html
到了这里,关于AI在 G-API 上移植各向异性图像分割(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!