项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching

kirin 980 CPU
Jetson Nano
Jetson Xavier NX
Jetson TX2
Xilinx ZCU104

0: koroFileHeader

https://blog.csdn.net/M1512415/article/details/116024395

vsCode插件(koroFileHeader),可快速生成注释模板
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第1张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第2张图片

"fileheader.configObj": { //快速添加文件头部注释和函数注释
        "createFileTime": true, // 设置为true则为文件新建时候作为date,否则注释生成时间为date
        "autoAdd": true, // 自动生成注释
        "annotationStr": {
            "head": "/*",
            "middle": " * @",
            "end": " */",
            "use": true // 设置自定义注释可用
        },
    },
    "fileheader.cursorMode": { // 快速注释函数 ctrl+alt+t
        "description": "", // 函数描述
        "param ": "", // 函数参数
        "return": "", // 函数输出
        "Author": "爱酱丶", // 作者
        "Date": "Do not edit", // 创建时间
        "LastEditTime": "Do not edit", // 最后一次修改的时间
        "LastEditors": "爱酱丶" // 修改人员
    },
    "fileheader.customMade": { // 快速注释文件头部 ctrl+alt+i
        "Description": "", // 文件描述
        "Author": "爱酱丶", // 作者
        "Date": "Do not edit", // 创建时间
        "LastEditTime": "Do not edit", // 最后一次修改的时间
        "LastEditors": "爱酱丶" // 修改人员
    }

函數
CTRL+Win+t
文件
CTRL+Win+i

1: Hyperlpr

早期Demo
zeusees/hyperlpr
git_demo

一键安装

python -m pip install hyperlpr

支持python3,支持Windows Mac Linux 树莓派等。

720p cpu real-time (st on MBP r15 2.2GHz haswell).

快速上手

#导入包
from hyperlpr import *
#导入OpenCV库
import cv2
#读入图片
image = cv2.imread("demo.jpg")
#识别结果
print(HyperLPR_plate_recognition(image))

传统方法:

CascadeClassifier是opencv下objdetect模块中用来做目标检测的级联分类器的一个类;简而言之是滑动窗口机制+级联分类器的方式;
opencv2和opencv3中提供了完整的cascade分类器的训练和检测方法
cv::CascadeClassifier cascade;

模型训练时候的特征featureType:可选HAAR或LBP,默认为HAAR;

info

cv::CascadeClassifier::detectMultiScale(
		const cv::Mat& image, // 输入待检测的图像(灰度)
		vector<cv::Rect>& objects, // 输出的目标窗口
		double scaleFactor = 1.1, // 尺度系数
		int minNeighbors = 3, // 需要的邻域数
		int flags = 0, // flag (旧风格的cascades)
		cv::Size minSize = cv::Size(), // 最小检测窗口
		cv::Size maxSize = cv::Size() // 最大检测窗口
	);

类似应用:

滑动窗口 + HOG+SVM可进行目标检测
HOG+SVM可进行目标分类

基本步骤

step1. 使用opencv 的 HAAR Cascade 检测车牌大致位置

step2. Extend 检测到的大致位置的矩形区域

step3. 使用类似于MSER的方式的 多级二值化 + RANSAC 拟合车牌的上下边界

step4. 使用CNN Regression回归车牌左右边界

method 1:
	step5. 使用基于纹理场的算法进行车牌校正倾斜
	
	step6. 使用CNN滑动窗切割字符
	
	step7. 使用CNN识别字符
method 2:

	step 5:CRNN字符识别
	 由CNN+BiLSTM+CTC构成

方法一:

输出两个边界点:
在这里插入图片描述

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第3张图片
输出84×20 :
在这里插入图片描述

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第4张图片
方法二:

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第5张图片
Train
CRNN_Chinese_Characters_Rec

https://www.cnblogs.com/wjy-lulu/p/11370541.html
支持类型

SEGMENTATION_FREE_METHOD
才支持绿牌,不定长数据
SEGMENTATION_BASED_METHOD
仅仅支持普通车牌识别,定长

可识别和待支持的车牌的类型
单行蓝牌
单行黄牌
新能源车牌
白色警用车牌
使馆/港澳车牌
教练车牌
武警车牌

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第6张图片

2: Apollo

主要基于最近的Apollo6.0讲述
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第7张图片

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第8张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第9张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第10张图片
CyberRT 就是 Apollo 中的一套基础框架,是面向组件(component)的。组件呈现高度的模块化。
https://frank909.blog.csdn.net/article/details/111598755

每个组件包含特定的算法,用于处理数据输入,并输出算法处理的结果。

玩过 ROS 的同学应该对此类东西不陌生,CyberRT 和 ROS 类似,实际上 Apollo 最初也是用的
ROS1,后来因为时延问题得不到满足,所以自行开发了一个类似的,但性能更好。

回到组件问题,Perception 也是组件,之前的文章有介绍,它接收传感器的数据,然后输出障碍物的 3D 信息。

在 CyberRT 中,有如何定义、实现、启动组件的机制说明。

组件管理

通常 4 个步骤进行组件开发:

设置组件文件结构 实现组件类 设置配置文件 启动组件

红绿灯感知

Apollo 中的红绿灯 Apollo 默认有 2 个前视摄像头:

25mm 焦距看远处,视距长,但 FOV 小。 6mm 焦距看近处,视距短,但 FOV 大。
两个摄像头都可以检测到红绿灯,它们相互冗余,但是同一时刻只能以一个为主。

识别策略:

在自动驾驶中,因为考虑到车辆行驶速度很快,因此障碍物的识别一般要求实时,也就是 30FPS 以上。

但相对于障碍物,红绿灯的位置信息没有那么重要,重要的是它的语义信息,也就是红绿颜色变化,但这种频率是非常低的,所以对于红绿灯检测而言,我们不需要那么高的频率,也因此不需要针对每一帧图片都做红绿灯处理。

因此,我们可以隔一个固定的时间周期去查询高精度地图中的红绿灯信息,然后选择最近的图片缓存一起送入到红绿灯处理模型当中,其它的图片就可以丢掉了。

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第11张图片

3: EasyPR

https://blog.csdn.net/u012156872/article/details/107728334
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第12张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第13张图片
车牌检测包括了车牌定位,检测是粗定位,定位的包括旋转的定位;项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第14张图片项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第15张图片
定位是一个综合体:
1:轮廓
2:颜色
3:字体
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第16张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第17张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第18张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第19张图片
针对opencv4,需要添加头文件:

error: ‘CV_CHAIN_APPROX_NONE’ was not declared in this scope

#include 

error: ‘CV_WINDOW_AUTOSIZE’ was not declared in this scope

#include 


在opencv3中可编译通过,但opencv4中无法编译,报错:

error: CV_COMP_CORREL was not declared in this scope.
是因为opencv4中CV_COMP_CORREL定义在types_c.h文件中,只需包含以下头文件即可。

#include 

4:freetype安装

FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件。在字体图片生成中常常会用到。

pip install freetype-py

5: Dark Channel Prior

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第20张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第21张图片

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第22张图片
① 暗通道定义

 何恺明 通过对大量在户外拍摄的自然景物图片进行统计分析得出一个结论:在绝大多数非天空的局部区域里,某一些像素总会(至少一个颜色通道)具有很低的值。换言之,该区域光强度的最小值是个很小的数(趋于0)。

基于上述结论,我们定义暗通道,用公式描述,对于一幅图像J有如下式子:

也就是说以像素点x为中心,分别取三个通道内窗口Ω内的最小值,然后再取三个通道的最小值作为像素点x的暗通道的值,如下图所示:

Jc代表J的某一个颜色通道,而Ω(x)是以x为中心的一块方形区域。我们观察得出,除了天空方位,Jdark的强度总是很低并且趋近于0。如果J是户外的无雾图像,我们把Jdark称为J的暗原色,并且把以上观察得出的经验性规律称为暗原色先验。

②大气物理模型
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第23张图片

要想从物理模型角度对有雾图像进行清晰化处理,就要了解有雾图像的物理成因,那么就要了解雾天的大气散射模型。

大气散射物理模型包含两部分,第一部分称为直接衰减项(Direct Attenuation)也称直接传播,第二部分称为大气光照(Airlight)

用公式表示如下:

I是观测到的有雾图像,J是景物反射光强度(也就是清晰的无雾图像),A是全局大气光照强度,t用来描述光线通过介质透射到成像设备过程中没有被散射的部分,去雾的目标就是从I中复原J。那么也就是要通过I求A和t。

方程右边的第一项J(x)t(x) 叫做直接衰减项,第二项A(1-t(x))则是大气光照。直接衰减项描述的是景物光线在透射媒介中经衰减后的部分,而大气光则是由前方散射引起的,会导致景物颜色的偏移。因为大气层可看成各向同性的,透射率t可表示为:

β为大气的散射系数,该式表明景物光线是随着景物深度d按指数衰减的。

③求解透射率t

在论文[1]中,作者给出了推导过程,这里就不再重复,其最后得到透射率t的公式如下:

Ic为输入的有雾图像,对其除以全局大气光照Ac后在利用暗通道定义公式进行求解暗通道。w(0

这里需要值得注意的是,求得的t是粗透射率图,并不能直接带入大气模型公式求解,所以需要进行细化后再处理。细化过程见⑤,Ac为全局大气光照,其求法见④。

④求解全局大气光照Ac

论文[1]中作者给出求解全局大气光照的过程如下:

1.首先对输入的有雾图像I求解其暗通道图像Jdark。

2.选择暗通道Jdark内图像总像素点个数(N_imagesize)千分之一(N=N_imagesize/1000)个最亮的像素点,并记录这些像素点(x,y)坐标。

3.再根据这些点的坐标分别在原图像I的三个通道(r,g,b)内找到这些像素点并加和得到(sum_r,sum_g,sum_b).

4.Ac=[Ar,Ag,Ab]. 其中Ar=sum_r/N; Ag=sum_g/N; Ab=sum_b/N.

⑤细化透射率t

⑥求解最后清晰图像

现在,我们得到了A和t,那么带入大气模型公式:

这里,t0参数用来限定透射率t的下限值,其作用也就是在输入图像的浓雾区域保留一定的雾。
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第24张图片

https://www.cnblogs.com/changkaizhao/p/3266798.html

其他应用:

引申到能见度评估:
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第25张图片

建立不依赖能见度仪观测数据的能见度估计算法,即通过视频/图像中的信息获取场景的能见度。通过查阅文献,能见度可以用消光系数求出,而消光系数可以通过区域的透射率和拍摄距离求得。因此,首先通过暗通道理论获取暗通道图像,再通过大气散射物理模型求得图像得透射率,再通过深度图获取目标物与观测点的距离,再用该距离与透射率求出消光系数,再利用公式求出能见度。

https://yuanwenjie.blog.csdn.net/article/details/110116319
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第26张图片
项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第27张图片

clc;
clear all;
close all;
J = imread('4.jpg');
J = double(J);
J = J ./255 ;
figure(1); imshow(J); 
%% 求暗通道图像 Jdark = min(min());
Jdark = Idark(J);
figure(2);imshow(Jdark,[]);
 
%%
% 注意:何凯明使用了soft matting方法对得到的粗透射率Jt进行细化 
%       本代码采用梯度导向滤波实现
Jdark = gradient_guidedfilter(Jdark,Jdark, 0.04);
figure(3);imshow(Jdark,[]);
%% 大气物理模型 J = I*t + A*(1-t)  【直接衰减项】+【大气光照】
% 透射率 t与深度的关系 t=exp(-a*depth)
w = 0.95;         %雾的保留系数
Jt = 1 - w*Jdark; %求解透射率
 
%% 求解全局大气光照
% 1.首先对输入的有雾图像I求解其暗通道图像Jdark。
% 2.选择Jdark总像素点个数千分之一(N/1000)个最亮的像素点,记录像素点(x,y)坐标
% 3.根据点的坐标分别在原图像J的三个通道(r,g,b)内找到这些像素点并加和得到(sum_r,sum_g,sum_b).
% 4.Ac=[Ar,Ag,Ab]. 其中Ar=sum_r/N;   Ag=sum_g/N;   Ab=sum_b/N.
[m,n,~] = size(J);
N = floor( m*n./1000 );
MaxPos = [0,0]; % 初始化
for i=1:1:N
    MaxValue = max(max(Jdark));
    [x,y] = find(Jdark==MaxValue);
    Jdack(Jdark==MaxValue) = 0; %最大值置零,寻找下一次次大值
    %检查长度
    MaxPos = vertcat(MaxPos,[x,y]);
    Cnt = length(MaxPos(1));
    if Cnt > N
        break;
    end
end
MaxPosN = MaxPos(2:N+1,:);
 
Rsum = 0;  Jr = J(:,:,1);
Gsum = 0;  Jg = J(:,:,2);
Bsum = 0;  Jb = J(:,:,3);
for j=1:1:N
    Rsum = Rsum + Jr(MaxPosN(j,1),MaxPosN(j,2));
    Gsum = Gsum + Jg(MaxPosN(j,1),MaxPosN(j,2));
    Bsum = Bsum + Jb(MaxPosN(j,1),MaxPosN(j,2));
end
 
Ac = [Rsum/N, Gsum/N, Bsum/N];


6: Panoramic Stitching

项目基础算法,Hyperlpr、Apollo、EasyPR、Haze Removal、Stitching_第28张图片

#include 
#include 
#include
#include "opencv2/opencv_modules.hpp"
#include 
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/timelapsers.hpp"
#include "opencv2/stitching/detail/camera.hpp"
#include "opencv2/stitching/detail/exposure_compensate.hpp"
#include "opencv2/stitching/detail/matchers.hpp"
#include "opencv2/stitching/detail/motion_estimators.hpp"
#include "opencv2/stitching/detail/seam_finders.hpp"
#include "opencv2/stitching/detail/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"
#includeusing namespace std;
using namespace cv;
using namespace cv::detail;
​
​
int main(int argc, char** argv)
{
    vector<Mat> imgs;
    ifstream fin("../img.txt");
    string img_name;
    while(getline(fin, img_name))
    {
        Mat img = imread(img_name);
        imgs.push_back(img);
    }int num_images = imgs.size();    //图像数量
    cout<<"图像数量为"<<num_images<<endl;
    cout<<"图像读取完毕"<<endl;
​
​
​
    Ptr<FeaturesFinder> finder;    //定义特征寻找器
    finder = new SurfFeaturesFinder();    //应用SURF方法寻找特征
    //finder = new OrbFeaturesFinder();    //应用ORB方法寻找特征
    vector<ImageFeatures> features(num_images);    //表示图像特征
    for (int i =0 ;i<num_images;i++)
        (*finder)(imgs[i], features[i]);    //特征检测
    cout<<"特征提取完毕"<<endl;
    vector<MatchesInfo> pairwise_matches;    //表示特征匹配信息变量
    BestOf2NearestMatcher matcher(false, 0.35f, 6, 6);    //定义特征匹配器,2NN方法
    matcher(features, pairwise_matches);    //进行特征匹配
    cout<<"特征匹配完毕"<<endl;

    HomographyBasedEstimator estimator;    //定义参数评估器
    vector<CameraParams> cameras;    //表示相机参数,内参加外参
    estimator(features, pairwise_matches, cameras);    //进行相机参数评
    for (size_t i = 0; i < cameras.size(); ++i)    //转换相机旋转参数的数据类型
    {
        Mat R;
        cameras[i].R.convertTo(R, CV_32F);
        cameras[i].R = R;
    }
    cout<<"相机参数预测完毕"<<endl;
​
​
    for (size_t i = 0; i < cameras.size(); ++i)
    {
        cout<<"第"<<i<<"焦距为"<<cameras[i].focal<<endl;
    }
    // 在一部可以计算重映射误差,想办法让他可以输出出来
    Ptr<detail::BundleAdjusterBase> adjuster;    //光束平差法,精确相机参数
    //adjuster->setRefinementMask();
    adjuster = new detail::BundleAdjusterReproj();    //重映射误差方法
    //adjuster = new detail::BundleAdjusterRay();    //射线发散误差方法
​
    adjuster->setConfThresh(1.0f);    //设置匹配置信度,该值设为1
    (*adjuster)(features, pairwise_matches, cameras);    //精确评估相机参数
​
    vector<Mat> rmats;
    for (size_t i = 0; i < cameras.size(); ++i)    //复制相机的旋转参数
        rmats.push_back(cameras[i].R.clone());
    waveCorrect(rmats, WAVE_CORRECT_HORIZ);    //进行波形校正
    for (size_t i = 0; i < cameras.size(); ++i)    //相机参数赋值
        cameras[i].R = rmats[i];
    rmats.clear();    //清变量
​
    cout<<"利用光束平差法进行相机矩阵更新"<<endl;
​
    vector<Point> corners(num_images);    //表示映射变换后图像的左上角坐标
    vector<UMat> masks_warped(num_images);    //表示映射变换后的图像掩码
    vector<UMat> images_warped(num_images);    //表示映射变换后的图像
    vector<Size> sizes(num_images);    //表示映射变换后的图像尺寸
    vector<UMat> masks(num_images);    //表示源图的掩码for (int i = 0; i < num_images; ++i)    //初始化源图的掩码
    {
        masks[i].create(imgs[i].size(), CV_8U);    //定义尺寸大小
        masks[i].setTo(Scalar::all(255));    //全部赋值为255,表示源图的所有区域都使用
    }
​
    Ptr<WarperCreator> warper_creator;    //定义图像映射变换创造器
    warper_creator = new cv::SphericalWarper();
    //warper_creator = makePtr();     //平面投影
    //warper_creator = new cv::CylindricalWarper();    //柱面投影
    //warper_creator = new cv::SphericalWarper();    //球面投影
    //warper_creator = new cv::FisheyeWarper();    //鱼眼投影
    //warper_creator = new cv::StereographicWarper();    //立方体投影//定义图像映射变换器,设置映射的尺度为相机的焦距,所有相机的焦距都相同
    vector<double> focals;
    for (size_t i = 0; i < cameras.size(); ++i)
    {
        cout<<"第"<<i<<"焦距为"<<cameras[i].focal<<endl;
        focals.push_back(cameras[i].focal);
    }
    sort(focals.begin(), focals.end());
    float warped_image_scale;
    if (focals.size() % 2 == 1)
        warped_image_scale = static_cast<float>(focals[focals.size() / 2]);
    else
        warped_image_scale = static_cast<float>(focals[focals.size() / 2 - 1] + focals[focals.size() / 2]) * 0.5f;
    Ptr<RotationWarper> warper = warper_creator->create(static_cast<float>(warped_image_scale));
    for (int i = 0; i < num_images; ++i)
    {
        Mat_<float> K;
        cameras[i].K().convertTo(K, CV_32F);    //转换相机内参数的数据类型
        //对当前图像镜像投影变换,得到变换后的图像以及该图像的左上角坐标
        corners[i] = warper->warp(imgs[i], K, cameras[i].R, INTER_LINEAR, BORDER_REFLECT, images_warped[i]);
        sizes[i] = images_warped[i].size();    //得到尺寸
        //得到变换后的图像掩码
        warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warped[i]);
    }
​
    imgs.clear();    //清变量
    masks.clear();
    cout<<"图像映射完毕"<<endl;
    //创建曝光补偿器,应用增益补偿方法
    Ptr<ExposureCompensator> compensator =
            ExposureCompensator::createDefault(ExposureCompensator::GAIN);
    compensator->feed(corners, images_warped, masks_warped);    //得到曝光补偿器
    for(int i=0;i<num_images;++i)    //应用曝光补偿器,对图像进行曝光补偿
    {
        compensator->apply(i, corners[i], images_warped[i], masks_warped[i]);
    }
    cout<<"图像曝光完毕"<<endl;

    //在后面,我们还需要用到映射变换图的掩码masks_warped,因此这里为该变量添加一个副本masks_seam
    vector<UMat> masks_seam(num_images);
    for(int i = 0; i<num_images;i++)
        masks_warped[i].copyTo(masks_seam[i]);
​
    Ptr<SeamFinder> seam_finder;    //定义接缝线寻找器
    //seam_finder = new NoSeamFinder();    //无需寻找接缝线
    //seam_finder = new VoronoiSeamFinder();    //逐点法
    //seam_finder = new DpSeamFinder(DpSeamFinder::COLOR);    //动态规范法
    //seam_finder = new DpSeamFinder(DpSeamFinder::COLOR_GRAD);
    //图割法
    seam_finder = new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR);
    //seam_finder = new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR_GRAD);
​
    vector<UMat> images_warped_f(num_images);
    for (int i = 0; i < num_images; ++i)    //图像数据类型转换
        images_warped[i].convertTo(images_warped_f[i], CV_32F);
​
    images_warped.clear();    //清内存
    //得到接缝线的掩码图像masks_seam
    seam_finder->find(images_warped_f, corners, masks_seam);
    for(size_t i = 0; i < num_images; i++)
    {
        namedWindow("mask_cut", WINDOW_NORMAL);
        imshow("mask_cut", masks_seam[i]);
        waitKey(0);
    }
​
​
    cout<<"拼缝优化完毕"<<endl;
​
    vector<Mat> images_warped_s(num_images);
    Ptr<Blender> blender;    //定义图像融合器
​
    blender = Blender::createDefault(Blender::NO, false);    //简单融合方法
    //羽化融合方法
//    blender = Blender::createDefault(Blender::FEATHER, false);
//    //dynamic_cast多态强制类型转换时候使用
//    FeatherBlender* fb = dynamic_cast(static_cast(blender));
//    fb->setSharpness(0.005);    //设置羽化锐度//    blender = Blender::createDefault(Blender::MULTI_BAND, false);    //多频段融合
 //   MultiBandBlender* mb = dynamic_cast(static_cast(blender));
 //   mb->setNumBands(8);   //设置频段数,即金字塔层数
​
    blender->prepare(corners, sizes);    //生成全景图像区域
    cout<<"生成全景图像区域"<<endl;
    vector<Mat> dilate_img(num_images);
    vector<Mat> masks_seam_new(num_images);
    Mat tem;
    Mat element = getStructuringElement(MORPH_RECT, Size(20, 20));    //定义结构元素
    for(int k=0;k<num_images;k++)
    {
        images_warped_f[k].convertTo(images_warped_s[k], CV_16S);    //改变数据类型
        dilate(masks_seam[k], masks_seam_new[k], element);    //膨胀运算
        //映射变换图的掩码和膨胀后的掩码相“与”,从而使扩展的区域仅仅限于接缝线两侧,其他边界处不受影响
        masks_warped[k].copyTo(tem);
        masks_seam_new[k] = masks_seam_new[k] & tem;
        blender->feed(images_warped_s[k], masks_seam_new[k], corners[k]);    //初始化数据
        cout<<"处理完成"<<k<<"图片"<<endl;
    }
​
    masks_seam.clear();    //清内存
    images_warped_s.clear();
    masks_warped.clear();
    images_warped_f.clear();
​
​
    Mat result, result_mask;
    //完成融合操作,得到全景图像result和它的掩码result_mask
    blender->blend(result, result_mask);
    imwrite("result.jpg", result);    //存储全景图像return 0;
}

你可能感兴趣的:(编程算法技巧,算法,opencv,计算机视觉)