人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域。这些感兴趣的区域称为显著性区域。视觉显著性检测(Visual Saliency Detection,VSD)则是一种模拟人类视觉并从图像中提取显著性区域的智能算法。如下面左边的图所示,人眼在观看该图片时会首先注意其中的小狗,自动忽略背景区域,小狗所在区域就是显著性区域。通过计算机视觉算法对左边的图像进行视觉显著性检测能够得到下图右边的结果,其中黑色区域为不显著区域,白色为显著区域,显著性检测在机器人领域、目标检测领域和图像识别领域有大量应用。

本文主要介绍基于OpenCV contrib库中的saliency模块实现视觉显著性检测算法,OpenCV contrib库中的saliency模块官方仓库见saliency。关于视觉显著性检测算法更多详细介绍见:图像显著性检测论文及代码汇总

本文需要OpenCV contrib库,OpenCV contrib库的编译安装见:

OpenCV_contrib库在windows下编译使用指南

本文所有代码见:

OpenCV-Practical-Exercise


1 OpenCV显著性算法背景介绍

1.1 OpenCV显著性检测算法相关信息介绍

OpenCV contrib库中的saliency模块提供四种显著性检测算法。本节主要介绍这四种方法的相关信息。

1.1.1 StaticSaliencySpectralResidual

  • 原理:该方法从自然图像统计原理出发,模拟注意前视觉搜索的行为。该算法对每幅图像的对数谱进行分析,得到谱残差SR (Spectral Residual)。然后将谱残差进行空间变换,得到显著性图,该显著性图显示了感兴趣目标的位置。
  • 论文:Saliency Detection: A Spectral Residual Approach
  • 提出时间:2007
  • 检测方式:单张图片检测

调用接口如下:

C++

saliencyAlgorithm = StaticSaliencySpectralResidual::create();
// 计算显著性
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);

Python

saliencyAlgorithm = cv2.saliency.StaticSaliencySpectralResidual_create()
# 计算显著性
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)

1.1.2 StaticSaliencyFineGrained

调用接口如下:

C++

saliencyAlgorithm = StaticSaliencyFineGrained::create();
// 计算显著性
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);

Python

saliencyAlgorithm = cv2.saliency.StaticSaliencyFineGrained_create()
# 计算显著性
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)

1.1.3 ObjectnessBING

调用接口如下:

C++

saliencyAlgorithm = ObjectnessBING::create();
vector<Vec4i> saliencyMap;
// 提取模型文件参数
saliencyAlgorithm.dynamicCast<ObjectnessBING>()->setTrainingPath(training_path);
// 将算法检测结果保存在Results文件夹内
saliencyAlgorithm.dynamicCast<ObjectnessBING>()->setBBResDir("Results");
// 计算显著性
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);

Python

saliencyAlgorithm = cv2.saliency.ObjectnessBING_create()
# 提取模型文件参数
saliencyAlgorithm.setTrainingPath(training_path)
# 将算法检测结果保存在Results文件夹内
saliencyAlgorithm.setBBResDir("Results")
# 计算显著性
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)

1.1.4 BinWangApr2014

调用接口如下:

C++

saliencyAlgorithm = MotionSaliencyBinWangApr2014::create();
// 设置数据结构大小
saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->setImagesize(image.cols, image.rows);
// 初始化
saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->init();
saliencyAlgorithm->computeSaliency(frame, saliencyMap);

Python

saliencyAlgorithm = cv2.saliency.MotionSaliencyBinWangApr2014_create()
# 设置数据结构大小
saliencyAlgorithm.setImagesize(image.shape[1], image.shape[0])
# 初始化
saliencyAlgorithm.init()
success, saliencyMap = saliencyAlgorithm.computeSaliency(frame)

1.2 OpenCV saliency模块整体说明

显著性检测算法与目标检测算法大大不同。显著性检测算法,只是判断图中有显著目标的区域,这些区域可能包含目标也可能不包含目标,因方法而异。类比人眼的观察方式,显著性检测算法是许多计算机视觉任务的第一步,检测出显著性区域后,对这些显著性区域进行进一步判断和预测。显著性检测算法通常检测速度较快,某些计算量大的算法如深度学习图像分类算法,可以只在显著性区域上运行,以缩小检测范围,加快检测速度,提高检测精度。

OpenCV saliency模块提供了四种不同的显著性检测方法,但是按方法类别只有三种。OpenCV saliency模块的类关系如下图所示:

OpenCV saliency模块提供的三种不同方法类别模块介绍如下:

  • Motion saliency模块:这类算法输入为连续的图像帧,通过运动检测算法对连续图像帧进行处理,然后对运动目标进行跟踪,最终将运动目标设置为显著区域。代表为BinWangApr2014算法。该类算法容易出现丢帧和鬼影情况,运动检测效果不如主流的运动检测算法,实际图像显著性检测效果一般。
  • Objectness模块:这类算法输入为单帧图像,通过计算得到大量的建议区域,并将这些建议区域作为显著性区域。代表为ObjectnessBING算法。该类算法检测速度较慢,实际检测出来的建议区域可能上万个,需要进行筛选,总体效果一般。
  • Static saliency模块:这类算法输入为单帧图像,通过图像特征和统计量来定位图像中的显著性区域。代表为StaticSaliencySpectralResidual和StaticSaliencyFineGrained。该类算法检测速度非常快,不过效果总体一般。

更多关于OpenCV saliency模块的介绍可以见:OpenCV中的显著性检测(Saliency Detection)OpenCV—python 显着性检测二

2 代码实现与结果分析

2.1 代码实现

本文所提供的代码可以对视频或者图像进行显著性检测,BinWangApr2014只能对视频进行显著性检测。本文提供C++和Python代码实现,代码如下:

C++

#include <opencv2/opencv.hpp>
#include <opencv2/saliency.hpp>
#include <iostream> using namespace std;
using namespace cv;
using namespace saliency; int main()
{
// 显著性检测算法
// 可选:SPECTRAL_RESIDUAL,FINE_GRAINED,BING,BinWangApr2014
String saliency_algorithm = "FINE_GRAINED";
// 检测视频或者图像
String video_name = "video/vtest.avi";
// String video_name = "video/dog.jpg";
// 起始帧
int start_frame = 0;
// 模型路径
String training_path = "ObjectnessTrainedModel"; // 如果算法名和视频名为空,停止检测
if (saliency_algorithm.empty() || video_name.empty())
{
cout << "Please set saliency_algorithm and video_name";
return -1;
} // open the capture
VideoCapture cap;
// 打开视频
cap.open(video_name);
// 设置视频起始帧
cap.set(CAP_PROP_POS_FRAMES, start_frame); // 输入图像
Mat frame; // instantiates the specific Saliency
// 实例化saliencyAlgorithm结构
Ptr<Saliency> saliencyAlgorithm; // 二值化检测结果
Mat binaryMap;
// 检测图像
Mat image; // 读图
cap >> frame;
if (frame.empty())
{
return 0;
} frame.copyTo(image); // 根据输入的方法确定检测类型
// StaticSaliencySpectralResidual
if (saliency_algorithm.find("SPECTRAL_RESIDUAL") == 0)
{
// 检测结果,白色区域表示显著区域
Mat saliencyMap;
saliencyAlgorithm = StaticSaliencySpectralResidual::create();
// 计算显著性
double start = static_cast<double>(getTickCount());
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeSaliency cost time is: " << duration * 1000 << "ms" << endl; if (success)
{
StaticSaliencySpectralResidual spec;
// 二值化图像
double start = static_cast<double>(getTickCount());
spec.computeBinaryMap(saliencyMap, binaryMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeBinaryMap cost time is: " << duration * 1000 << "ms" << endl; imshow("Original Image", image);
imshow("Saliency Map", saliencyMap);
imshow("Binary Map", binaryMap); // 转换格式才能保存图片
saliencyMap.convertTo(saliencyMap, CV_8UC3, 256);
imwrite("Results/SPECTRAL_RESIDUAL_saliencyMap.jpg", saliencyMap);
imwrite("Results/SPECTRAL_RESIDUAL_binaryMap.jpg", binaryMap);
waitKey(0);
}
} // StaticSaliencyFineGrained
else if (saliency_algorithm.find("FINE_GRAINED") == 0)
{
Mat saliencyMap;
saliencyAlgorithm = StaticSaliencyFineGrained::create();
// 计算显著性
double start = static_cast<double>(getTickCount());
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeSaliency cost time is: " << duration * 1000 << "ms" << endl; if (success)
{
StaticSaliencyFineGrained spec;
// 二值化图像
// 二值化图像
double start = static_cast<double>(getTickCount());
spec.computeBinaryMap(saliencyMap, binaryMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeBinaryMap cost time is: " << duration * 1000 << "ms" << endl; imshow("Saliency Map", saliencyMap);
imshow("Original Image", image);
imshow("Binary Map", binaryMap); // 转换格式才能保存图片
saliencyMap.convertTo(saliencyMap, CV_8UC3, 256);
imwrite("Results/FINE_GRAINED_saliencyMap.jpg", saliencyMap);
imwrite("Results/FINE_GRAINED_binaryMap.jpg", binaryMap);
waitKey(0);
}
} // ObjectnessBING
else if (saliency_algorithm.find("BING") == 0)
{
// 判断模型是否存在
if (training_path.empty())
{
cout << "Path of trained files missing! " << endl;
return -1;
} else
{
saliencyAlgorithm = ObjectnessBING::create();
vector<Vec4i> saliencyMap;
// 提取模型文件参数
saliencyAlgorithm.dynamicCast<ObjectnessBING>()->setTrainingPath(training_path);
// 将算法检测结果保存在Results文件夹内
saliencyAlgorithm.dynamicCast<ObjectnessBING>()->setBBResDir("Results"); // 计算显著性
double start = static_cast<double>(getTickCount());
bool success = saliencyAlgorithm->computeSaliency(image, saliencyMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeSaliency cost time is: " << duration * 1000 << "ms" << endl; if (success)
{
// saliencyMap获取检测到的目标个数
int ndet = int(saliencyMap.size());
std::cout << "Objectness done " << ndet << std::endl;
// The result are sorted by objectness. We only use the first maxd boxes here.
// 目标按可能性从大到小排列,maxd为显示前5个目标,step设置颜色,jitter设置矩形框微调
int maxd = 5, step = 255 / maxd, jitter = 9;
Mat draw = image.clone();
for (int i = 0; i < std::min(maxd, ndet); i++)
{
// 获得矩形框坐标点
Vec4i bb = saliencyMap[i];
// 设定颜色
Scalar col = Scalar(((i*step) % 255), 50, 255 - ((i*step) % 255));
// 矩形框微调
Point off(theRNG().uniform(-jitter, jitter), theRNG().uniform(-jitter, jitter));
// 画矩形
rectangle(draw, Point(bb[0] + off.x, bb[1] + off.y), Point(bb[2] + off.x, bb[3] + off.y), col, 2);
// mini temperature scale
// 颜色标注
rectangle(draw, Rect(20, 20 + i * 10, 10, 10), col, -1);
}
imshow("BING", draw); // 保存图片
imwrite("Results/BING_draw.jpg", draw);
waitKey();
}
else
{
std::cout << "No saliency found for " << video_name << std::endl;
}
}
} // BinWangApr2014
else if (saliency_algorithm.find("BinWangApr2014") == 0)
{
saliencyAlgorithm = MotionSaliencyBinWangApr2014::create();
// 设置数据结构大小
saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->setImagesize(image.cols, image.rows);
// 初始化
saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->init(); bool paused = false;
for (;; )
{
if (!paused)
{
cap >> frame;
if (frame.empty())
{
return 0;
}
cvtColor(frame, frame, COLOR_BGR2GRAY); Mat saliencyMap;
// 计算
double start = static_cast<double>(getTickCount());
saliencyAlgorithm->computeSaliency(frame, saliencyMap);
double duration = ((double)getTickCount() - start) / getTickFrequency();
cout << "computeSaliency cost time is: " << duration * 1000 << "ms" << endl; imshow("image", frame);
// 显示
imshow("saliencyMap", saliencyMap * 255);
} char c = (char)waitKey(2);
if (c == 'q')
break;
if (c == 'p')
paused = !paused;
}
} destroyAllWindows();
return 0;
}

Python

# -*- coding: utf-8 -*-
"""
Created on Mon Sep 15 19:22:58 2020 @author: luohenyueji
""" import cv2
import random def main():
# 显著性检测算法
# 可选:SPECTRAL_RESIDUAL,FINE_GRAINED,BING,BinWangApr2014
saliency_algorithm = "FINE_GRAINED"
# 检测视频或者图像
video_name = "video/vtest.avi"
# video_name = "video/dog.jpg";
# 起始帧
start_frame = 0
# 模型路径
training_path = "ObjectnessTrainedModel" # 如果算法名和视频名为空,停止检测
if saliency_algorithm is None or video_name is None:
print("Please set saliency_algorithm and video_name")
return # open the capture
cap = cv2.VideoCapture(video_name) # 设置视频起始帧
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame) # 读图
_, frame = cap.read()
if frame is None:
print("Please set saliency_algorithm and video_name")
return image = frame.copy() # 根据输入的方法确定检测类型
if saliency_algorithm.find("SPECTRAL_RESIDUAL") == 0: # 检测结果,白色区域表示显著区域
saliencyAlgorithm = cv2.saliency.StaticSaliencySpectralResidual_create() # 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000)) if success:
# 二值化图像
start = cv2.getTickCount()
_, binaryMap = saliencyAlgorithm.computeBinaryMap(saliencyMap)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000)) cv2.imshow("Saliency Map", saliencyMap)
cv2.imshow("Original Image", image)
cv2.imshow("Binary Map", binaryMap) # 转换格式才能保存图片
saliencyMap = (saliencyMap * 255)
cv2.imwrite("Results/FINE_GRAINED_saliencyMap.jpg", saliencyMap)
cv2.imwrite("Results/FINE_GRAINED_binaryMap.jpg", binaryMap)
cv2.waitKey(0) # FINE_GRAINED
elif saliency_algorithm.find("FINE_GRAINED") == 0:
saliencyAlgorithm = cv2.saliency.StaticSaliencyFineGrained_create() # 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
if success:
# 二值化图像
start = cv2.getTickCount()
_, binaryMap = saliencyAlgorithm.computeBinaryMap(saliencyMap)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000)) cv2.imshow("Saliency Map", saliencyMap)
cv2.imshow("Original Image", image)
cv2.imshow("Binary Map", binaryMap) # 转换格式才能保存图片
saliencyMap = (saliencyMap * 255)
cv2.imwrite("Results/FINE_GRAINED_saliencyMap.jpg", saliencyMap)
cv2.imwrite("Results/FINE_GRAINED_binaryMap.jpg", binaryMap)
cv2.waitKey(0) elif saliency_algorithm.find("BING") == 0:
# 判断模型是否存在
if training_path is None:
print("Path of trained files missing! ")
return
else:
saliencyAlgorithm = cv2.saliency.ObjectnessBING_create()
# 提取模型文件参数
saliencyAlgorithm.setTrainingPath(training_path)
# 将算法检测结果保存在Results文件夹内
saliencyAlgorithm.setBBResDir("Results") # 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(image)
duration = (cv2.getTickCount() - start) / cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
if success:
# saliencyMap获取检测到的目标个数
ndet = saliencyMap.shape[0]
print("Objectness done ", ndet) # The result are sorted by objectness. We only use the first maxd boxes here.
# 目标按可能性从大到小排列,maxd为显示前5个目标,step设置颜色,jitter设置矩形框微调
maxd = 5
step = 255 / maxd
jitter = 9
draw = image.copy() for i in range(0, min(maxd, ndet)):
# 获得矩形框坐标点
bb = saliencyMap[i][0]
# 设定颜色
col = ((i * step) % 255), 50, 255 - ((i * step) % 255)
# 矩形框微调
off = random.randint(-jitter,
jitter), random.randint(-jitter, jitter)
# 画矩形
cv2.rectangle(draw, (bb[0] + off[0], bb[1] + off[1]),
(bb[2] + off[0], bb[3] + off[1]), col, 2)
# mini temperature scale
# 颜色标注
cv2.rectangle(draw, (20, 20 + i * 10, 10, 10), col, -1) # 保存图片
cv2.imwrite("Results/BING_draw.jpg", draw)
cv2.imshow("BING", draw)
cv2.waitKey(0) # 需要传入图像建模
elif saliency_algorithm.find("BinWangApr2014") == 0:
saliencyAlgorithm = cv2.saliency.MotionSaliencyBinWangApr2014_create()
# 设置数据结构大小
saliencyAlgorithm.setImagesize(image.shape[1], image.shape[0])
# 初始化
saliencyAlgorithm.init()
paused = False while True:
if not paused:
_, frame = cap.read()
if frame is None:
break frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 计算显著性
start = cv2.getTickCount()
success, saliencyMap = saliencyAlgorithm.computeSaliency(frame)
duration = (cv2.getTickCount() - start) / \
cv2.getTickFrequency()
print("computeBinaryMap cost time is: {} ms".format(duration * 1000))
cv2.imshow("image", frame)
# 显示
cv2.imshow("saliencyMap", saliencyMap * 255) c = cv2.waitKey(2)
c = chr(c) if c != -1 else 0
if c == 'q':
break
if c == 'p':
paused = not paused cv2.destroyAllWindows()
return if __name__ == '__main__':
main()

2.2 结果分析

2.2.1 图片检测结果

对单张图片检测进行显著性区域检测后的结果如下所示:

类型 图片(487X365) 单帧处理时间/ms
原图 -
StaticSaliencySpectralResidual 2.8
StaticSaliencyFineGrained 53.7
ObjectnessBING 411.7

此外为了提高可视化结果,对StaticSaliencySpectralResidual和StaticSaliencyFineGrained的显著性检测结果图片进行了二值化,主要通过StaticSaliency::computeBinaryMap实现,即先聚类然后阈值分割。结果如下所示:

类型 图片 单帧处理时间/ms
StaticSaliencySpectralResidual 48.4
StaticSaliencyFineGrained 52.4

2.2.2 视频检测结果

对视频进行检测,StaticSaliencySpectralResidual,StaticSaliencyFineGrained,ObjectnessBING就是对每帧进行检测;MotionSaliencyBinWangApr2014就是对每帧图片进行运动建模和显著性检测。取视频第100帧显著性检测结果,结果如下所示:

类型 图片(768X576) 单帧处理时间/ms
原图 -
StaticSaliencySpectralResidual 3.2
StaticSaliencyFineGrained 119.2
ObjectnessBING 986.5
MotionSaliencyBinWangApr2014 65.1

二值化结果如下所示:

类型 图片 单帧处理时间/ms
StaticSaliencySpectralResidual 120.125
StaticSaliencyFineGrained 138.783

2.2.3 效果评价

可以很认真的说,OpenCV contrib库中的saliency模块所提供的视觉显著性检测算法效果都很差,这个效果很差主要是现实落地上的意义,可以进行大规模测试。具体来说OpenCV提供的视觉显著性检测算法都只能应用于简单场景,复杂场景很容易出错,而且精度不如直接用目标识别来的快。当然现有的视觉显著性检测算法效果都很差,都无法实用,具体介绍可见:视觉图像显著性检测综述

如果非要对OpenCV contrib库中的saliency模块所提供的视觉显著性检测算法进行评价,个人感觉如下:

  1. 按速度而言StaticSaliencySpectralResidual效果最好,但是效果很差。ObjectnessBING速度上最慢,但是实际画框太多,靠运气成分决定效果。
  2. StaticSaliencyFineGrained效果和速度都还不错,但是StaticSaliencyFineGrained获得的结果是一个高维图像,需要进行二值化转换。模块自带的computeBinaryMap函数进行二值化效果很不错,但是耗时,如果想要快速获得结果,直接阈值化即可。
  3. MotionSaliencyBinWangApr2014加入了运动检测,效果和速度都很不错,但是建模时间过长,而且很容易出现鬼影,所以实际使用可以建模一段时间再使用,当运动检测算法也不错。
  4. 几乎所有的显著性检测算法随着图像分辨率变大,检测时间变的越长,所以将图片预处理缩小到一定分辨率以提高检测速度是很有必要的。
  5. 如果是复杂场景,最好不要用显著性检测算法,效果极差。

3 参考

3.1 参考代码

3.2 参考论文

3.2 参考文档

[OpenCV实战]47 基于OpenCV实现视觉显著性检测的更多相关文章

  1. [OpenCV实战]48 基于OpenCV实现图像质量评价

    本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...

  2. [OpenCV实战]38 基于OpenCV的相机标定

    文章目录 1 什么是相机标定? 2 图像形成几何学 2.1 设定 2.1.1 世界坐标系 2.1.2 相机坐标系 2.1.3 图像坐标系 2.2 图像形成方法总结 3 基于OpenCV的相机标定原理 ...

  3. [OpenCV实战]45 基于OpenCV实现图像哈希算法

    目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...

  4. [OpenCV实战]28 基于OpenCV的GUI库cvui

    目录 1 cvui的使用 1.1 如何在您的应用程序中添加cvui 1.2 基本的"hello world"应用程序 2 更高级的应用 3 代码 4 参考 有很多很棒的GUI库,例 ...

  5. [OpenCV实战]5 基于深度学习的文本检测

    目录 1 网络加载 2 读取图像 3 前向传播 4 处理输出 3结果和代码 3.1结果 3.2 代码 参考 在这篇文章中,我们将逐字逐句地尝试找到图片中的单词!基于最近的一篇论文进行文字检测. EAS ...

  6. [OpenCV实战]26 基于OpenCV实现选择性搜索算法

    目录 1 背景 1.1 目标检测与目标识别 1.2 滑动窗口算法 1.3 候选区域选择算法 2 选择性搜索算法 2.1 什么是选择性搜索? 2.2 选择性搜索相似性度量 2.3 结果 3 代码 4 参 ...

  7. [OpenCV实战]51 基于OpenCV实现图像极坐标变换与逆变换

    在图像处理领域中,经常通过极坐标与笛卡尔直角坐标的互转来实现图像中圆形转为方形,或者通过极坐标反变换实现方形转圆形.例如钟表的表盘,人眼虹膜,医学血管断层都需要用到极坐标变换来实现圆转方. 文章目录 ...

  8. [OpenCV实战]11 基于OpenCV的二维码扫描器

    目录 1 二维码(QRCode)扫描 2 结果 3 参考 在这篇文章中,我们将看到如何使用OpenCV扫描二维码.您将需要OpenCV3.4.4或4.0.0及更高版本来运行代码. 1 二维码(QRCo ...

  9. paper 27 :图像/视觉显著性检测技术发展情况梳理(Saliency Detection、Visual Attention)

    1. 早期C. Koch与S. Ullman的研究工作. 他们提出了非常有影响力的生物启发模型. C. Koch and S. Ullman . Shifts in selective visual ...

随机推荐

  1. SpringBoot+MyBatis Plus对Map中Date格式转换的处理

    在 SpringBoot 项目中, 如何统一 JSON 格式化中的日期格式 问题 现在的关系型数据库例如PostgreSQL/MySQL, 都已经对 JSON 类型提供相当丰富的功能, 项目中对于不需 ...

  2. Docker 部署 Kibana

    Docker 部署 Kibana 本篇主要介绍 使用 Docker 部署 kibana 用于操作 Elasticsearch 使用. 1. 前置准备 1.1 Elasticsearch 准备 可以先准 ...

  3. 从SVN导出项目出现的乱码问题

    解决的方法很简单,只需要将Eclipse的编码标准设置为UTF-8即可 1.Window->Preferences->General->Workspace   面板Text file ...

  4. Linux 下指定端口开放访问权限

    Linux 下指定端口开放访问权限 作者:Grey 原文地址: 博客园:Linux 下指定端口开放访问权限 CSDN:Linux 下指定端口开放访问权限 环境 CentOS 系和 Debian 系的防 ...

  5. 经典排序算法之-----选择排序(Java实现)

    其他的经典排序算法链接地址:https://blog.csdn.net/weixin_43304253/article/details/121209905 选择排序思想: 思路: 1.从整个数据中挑选 ...

  6. 那齐博x3又什么什么?

    那齐博x3又什么什么? 齐博x3是齐博X1/齐博x2之后的升级版本. 主要优化圈子系统

  7. Conda的使用

    conda常用的命令 在Anaconda Powershell Prompt 输入: 1.conda -V检验是否安装及当前conda的版本. 2.conda list查看安装了哪些包 3.conda ...

  8. 十一、Pod的健康检查-探针

    Pod 的健康检查-探针 一.Pod 的健康检查-探针 1.1.探针基本概念 ​探针是由 kubelet 对容器执行的定期诊断.要执行诊断,kubelet 调用由容器实现的 Handler 有三种类型 ...

  9. 恭喜磊哥喜提n+1

    昨天下午两点多磊哥突然喊我下楼,第一反应是"这孙子,抽烟就直说,还说个事,你以外你是吉祥村大姐啊". 心里骂完以后我慢慢悠悠下楼了,见他在打电话我先默默点上一支,准备待他结束以后对 ...

  10. Java多线程的几种创建方式

    方法一:继承Thread类,重写run方法,直接调用start方法开启线程. /** * 继承Thread类,直接调用start方法开启线程. * @author LuRenJia */ public ...