AI在 G-API 上移植各向异性图像分割(一)

介绍

在本教程中,您将学习:

  • 如何将现有算法转换为 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 到 180
intHighThr = 57;// threshold2 表示方向,范围为 0 到 180
示例::addSamplesDataSearchSubDirectory“doc/tutorials/imgproc/anisotropic_image_segmentation/images”);
子 imgIn = imreadsamples::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_MINMAXCV_8U);
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAXCV_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;
输入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_32FSize(w, w));
boxFilter(imgDiffYY, J22, CV_32FSize(w, w));
boxFilter(imgDiffXY, J12, CV_32FSize(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() 显然是一个图像处理管道:

考虑到上述情况,calcGST() 是一个很好的候选者。在原始代码中,它的原型是这样定义的:

void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w);

使用 G-API,我们可以将其定义如下:

void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w);

重要的是要了解,基于 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::GMatautoimgimgDiffX

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_32Fcv::Size(w, w));
自动J22 = cv::gapi::boxFilter(imgDiffYY, CV_32Fcv::Size(w, w));
自动J12 = cv::gapi::boxFilter(imgDiffXY, CV_32Fcv::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_MINMAXCV_8U);
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAXCV_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::Mats
cv::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 管道的结果与原始结果完全匹配(给定相同的输入图像):

结果.jpg

使用 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 到 180
intHighThr = 57;// threshold2 表示方向,范围为 0 到 180
cv::Mat imgIn = cv::imread(“输入.jpg”cv::IMREAD_GRAYSCALE );
如果 (imgIn.empty()) //检查图片是否加载成功
{
std::cout << “错误:无法加载图像..!!” << std::endl;
返回 -1;
}
计算梯度结构张量,并使用 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::Mats
cv::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);
返回 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_32Fcv::Size(w, w));
自动J22 = cv::gapi::boxFilter(imgDiffYY, CV_32Fcv::Size(w, w));
自动J12 = cv::gapi::boxFilter(imgDiffXY, CV_32Fcv::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);
}

   在线教程

有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

请添加图片描述

人工智能书籍

第一阶段:零基础入门(3-6个月)

新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。

第二阶段:基础进阶(3-6个月)

熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。

第三阶段:工作应用

这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。

 有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值