07_图像卷积-filter2d.cpp
08_Sobel算子.cpp
09_Scharr算子.cpp
10_拉普拉斯算子.cpp
11_找你妹案例.cpp
12_形态学变化.cpp
注:文中部分知识点截取自课件,侵删!
2. 创建cmake文件夹,将 FindOpenCV.cmake 文件放入
# once done, this will define
#OpenCV_FOUND - whether there is OpenCV in the prebuilt libraries
#OpenCV_INCLUDE_DIRS - include directories for OpenCV
#OpenCV_LIBRARY_DIRS - library directories for OpenCV
#OpenCV_LIBRARIES - link this to use OpenCV
unset(OpenCV_FOUND)
# set( ... [PARENT_SCOPE])
# Signatures of this command that specify a ... placeholder expect zero or more arguments.
# Multiple arguments will be joined as a semicolon-separated list to form the actual variable value to be set.
# Zero arguments will cause normal variables to be unset.
# 指定项目依赖库所在的路径变量,这里都放在 /robotDepends/libs目录下
# /home/jacob/devtools/robotDepends/libs/opencv_3.4.12/libs
set(PREBUILT_DIR /home/jacob/devtools/robotDepends/libs)
# 指定opencv头文件库文件所在的路径变量,这里放在 /libs/opencv_3.4.12目录下
set(OpenCV_DIR ${
PREBUILT_DIR}/opencv_3.4.12)
MESSAGE(STATUS "TEST ${PREBUILT_DIR}")
# 指定opencv头文件所在的路径变量,这里放在 /opencv_3.4.12/include目录下
set(OpenCV_INCLUDE_DIRS ${
OpenCV_DIR}/include)
# eg: set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"
set(OpenCV_LIB_COMPONENTS
opencv_videostab;
opencv_video;
opencv_superres;
opencv_stitching;
opencv_photo;
opencv_objdetect;
opencv_ml;
opencv_imgproc;
opencv_highgui;
opencv_flann;
opencv_features2d;
opencv_core;
opencv_calib3d;
opencv_xfeatures2d;
opencv_imgcodecs)
# This command is used to find a directory containing the named file.
# find_path (
# <VAR>
# name | NAMES name1 [name2 ...]
# [HINTS path1 [path2 ... ENV var]]
# [CMAKE_FIND_ROOT_PATH_BOTH |
# ONLY_CMAKE_FIND_ROOT_PATH |
# NO_CMAKE_FIND_ROOT_PATH]
# )
find_path(OpenCV_INCLUDE_DIRS NAMES opencv.h HINTS ${
OpenCV_DIR}/include NO_SYSTEM_ENVIRONMENT_PATH)
set(OpenCV_LIBRARY_DIRS ${
OpenCV_DIR}/lib)
FOREACH (cvcomponent ${
OpenCV_LIB_COMPONENTS})
find_library(lib_${
cvcomponent} NAMES ${
cvcomponent} HINTS ${
OpenCV_DIR}/lib NO_DEFAULT_PATH)
set(OpenCV_LIBRARIES ${
OpenCV_LIBRARIES};${
lib_${
cvcomponent}})
ENDFOREACH ()
set(OpenCV_LIBS ${
OpenCV_LIBRARIES})
set(OpenCV_INCLUDE_DIRS
${
OpenCV_INCLUDE_DIRS};
${
OpenCV_INCLUDE_DIRS}/opencv)
if (OpenCV_INCLUDE_DIRS AND OpenCV_LIBRARIES)
set(OpenCV_FOUND TRUE)
endif (OpenCV_INCLUDE_DIRS AND OpenCV_LIBRARIES)
if (OpenCV_FOUND)
if (NOT OpenCV_FIND_QUIETLY)
message(STATUS "Found OpenCV: ${OpenCV_LIBRARIES}")
endif (NOT OpenCV_FIND_QUIETLY)
else (OpenCV_FOUND)
if (OpenCV_FIND_REQUIRED)
message(FATAL_ERROR "Could not find the OpenCV library")
endif ()
endif (OpenCV_FOUND)
# 导入opencv相关的头文件
include_directories(${
OpenCV_INCLUDE_DIRS})
3. 修改cmakelist.txt
cmake_minimum_required(VERSION 3.17)
project(studyopencv002)
set(CMAKE_CXX_STANDARD 14)
# load opencv files under cmake directory
set(CMAKE_MODULE_PATH ${
CMAKE_MODULE_PATH}/cmake)
# find dependencies for opencv
find_package(OpenCV REQUIRED)
add_executable(studyopencv002 main.cpp)
target_link_libraries(studyopencv002 ${
OpenCV_LIBS})
4. 源代码中导入 opencv 头文件,运行测试
#include
#include
using namespace std;
int main() {
std::cout << "Hello, World!" << std::endl;
// 1. read image
string fileName = "../img/lena.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
// 2. display image, wait key press
cv::imshow("src", src);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
/home/jacob/CVWS/studyopencv002/cmake-build-debug/studyopencv002
Hello, World!
需求
学会使用 opencv 原生的日志库函数。
代码
//
// Created by jacob on 12/29/20.
//
#include
#include
#include
using namespace std;
namespace cvlog = cv::utils::logging;
int main(int argc, char **argv) {
// setting up cv log
cvlog::setLogLevel(cvlog::LOG_LEVEL_INFO);
cv::Mat img = cv::Mat::eye(3, 3, CV_8U);
// logging method 1 (X)
char logMsg[] = "";
sprintf(logMsg, "img.type(): %d str: %s", img.type(), "abc");
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_INFO, logMsg);
// logging method 2 (X)
std::stringstream ss;
ss << "img.type(): " << img.type();
const char *str = ss.str().c_str();
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_WARNING, str);
// logging method 3 (recommanded)
CV_LOG_INFO(NULL, "hello: " << 32)
CV_LOG_INFO(ABC, "hello: " << img.type())
CV_LOG_WARNING(XYZ, "warning: " << img.type() << 32)
return 0;
}
解释说明
使用 logger.hpp 中定义的 日志宏 如:CV_LOG_INFO,CV_LOG_WARNING 等写日志。
代码
//
// Created by jacob on 12/29/20.
// enable cv-logging::https://stackoverflow.com/questions/54828885/how-to-enable-logging-for-opencv
//
#include
#include
#include
using namespace std;
int main() {
// 0. set logging
cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_INFO, "hello");
// 1. read image
string fileName = "../img/lena.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
// 2. do convolution
cv::Mat dst;
cv::Mat kernel = (cv::Mat_<char>(3, 3)
<< -1, -1, -1,
-1, 9, -1,
-1, -1, -1);
cv::filter2D(src, dst, -1, kernel);
// display & wait key press
cv::imshow("src", src);
cv::imshow("dst", dst);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
解释说明
需要使用 opencv 的日志功能,步骤:
#include
cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cv::utils::logging::internal::writeLogMessage(cv::utils::logging::LOG_LEVEL_INFO, "hello");
此程序中的卷积核对图形进行锐化处理
// 锐化滤波卷积核
cv::Mat kernel = (cv::Mat_<char>(3, 3)
<< -1, -1, -1,
-1, 9, -1,
-1, -1, -1);
代码
//
// Created by jacob on 12/29/20.
// enable cv-logging::https://stackoverflow.com/questions/54828885/how-to-enable-logging-for-opencv
//
#include
#include
#include
using namespace std;
namespace cvlog = cv::utils::logging;
int main() {
// 0. set logging
cvlog::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_INFO, "hello");
// 1. read src image
// string fileName = "../img/zqbb.jpg";
string fileName = "../img/lena.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
// 2. do Sobel
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
CV_LOG_INFO(NULL, "gray.type(): " << gray.type())
cv::Mat dst_x_v;
cv::Mat dst_y_h;
cv::Mat dst;
// 使用 -1 参数使得像素的取值范围在(CV_8U) 0-255,图像处理是会丢失信息
// cv::Sobel(gray, dst_x_v, -1, 1, 0);
// cv::Sobel(gray, dst_y_h, -1, 0, 1);
// dst = dst_x_v + dst_y_h;
// 将图像转化为 CV_16S 对图像进行处理,取值范围 2^16,不会丢失信息
cv::Sobel(gray, dst_x_v, CV_16S, 1, 0);
cv::convertScaleAbs(dst_x_v, dst_x_v);
cv::Sobel(gray, dst_y_h, CV_16S, 0, 1);
cv::convertScaleAbs(dst_y_h, dst_y_h);
cv::add(dst_x_v, dst_y_h, dst);
cv::convertScaleAbs(dst, dst);
// display & wait key press
cv::namedWindow("src", cv::WINDOW_NORMAL);
cv::imshow("src", src);
cv::imshow("gray", gray);
cv::imshow("dst_x_v", dst_x_v);
cv::imshow("dst_y_h", dst_y_h);
cv::imshow("dst", dst);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
解释说明
convertScaleAbs
将图像矩阵中的每一个像素点进行三个操作:1. 比例、2.计算绝对值、3.将像素转换成 CV_8U 类型,以防止数据溢出:
Scales, calculates absolute values, and converts the result to 8-bit.
On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type:
运行结果
使用 CV_16S 处理的图像,信息保留更多
代码
//
// Created by jacob on 12/29/20.
// enable cv-logging::https://stackoverflow.com/questions/54828885/how-to-enable-logging-for-opencv
//
#include
#include
#include
using namespace std;
namespace cvlog = cv::utils::logging;
int main() {
// 0. set logging
cvlog::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_INFO, "hello");
// 1. read src image
// string fileName = "../img/zqbb.jpg";
string fileName = "../img/lena.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
// 2. do Scharr
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
CV_LOG_INFO(NULL, "gray.type(): " << gray.type())
cv::Mat dst_x_v;
cv::Mat dst_y_h;
cv::Mat dst;
cv::Scharr(gray, dst_x_v, CV_16S, 1, 0);
cv::convertScaleAbs(dst_x_v, dst_x_v);
cv::Scharr(gray, dst_y_h, CV_16S, 0, 1);
cv::convertScaleAbs(dst_y_h, dst_y_h);
cv::add(dst_x_v, dst_y_h, dst);
// display & wait key press
cv::namedWindow("src", cv::WINDOW_NORMAL);
cv::imshow("src", src);
cv::imshow("gray", gray);
cv::imshow("dst_x_v", dst_x_v);
cv::imshow("dst_y_h", dst_y_h);
cv::imshow("dst", dst);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
运行结果
代码
//
// Created by jacob on 12/29/20.
// enable cv-logging::https://stackoverflow.com/questions/54828885/how-to-enable-logging-for-opencv
//
#include
#include
#include
using namespace std;
namespace cvlog = cv::utils::logging;
int main() {
// 0. set logging
cvlog::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_INFO, "hello");
// 1. read src image
// string fileName = "../img/zqbb.jpg";
string fileName = "../img/lena.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
// 2. do laplacian
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
CV_LOG_INFO(NULL, "gray.type(): " << gray.type())
cv::Mat dst;
cv::Laplacian(gray, dst, CV_16S, 5);
cv::convertScaleAbs(dst, dst); // 防止数据溢出,变成全灰图像
// display & wait key press
cv::namedWindow("src", cv::WINDOW_NORMAL);
cv::imshow("src", src);
cv::imshow("gray", gray);
cv::imshow("dst", dst);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
模板匹配
上下采样
代码
//
// Created by jacob on 12/29/20.
// enable cv-logging::https://stackoverflow.com/questions/54828885/how-to-enable-logging-for-opencv
//
#include
#include
#include
using namespace std;
using namespace cv;
namespace cvlog = cv::utils::logging;
int main() {
// 0. set logging
cvlog::setLogLevel(cv::utils::logging::LOG_LEVEL_INFO);
cvlog::internal::writeLogMessage(cvlog::LOG_LEVEL_INFO, "hello");
// 1. read src image
string fileName = "../img/zhaonimei.jpg";
string fileName_t = "../img/mei.jpg";
cv::Mat src = cv::imread(fileName, cv::IMREAD_COLOR);
cv::Mat temp = cv::imread(fileName_t, cv::IMREAD_COLOR);
// 2. do template matching
// 上采样
pyrUp(temp,temp);
// 模板匹配
Mat result;
matchTemplate(src,temp,result,TM_SQDIFF);
// 找到最小的匹配结果
double minVal=0;
double maxVal=0;
Point minLoc;
Point maxLoc;
minMaxLoc(result,&minVal,&maxVal,&minLoc,&maxLoc);
cout<<minVal<<endl;
cout<<minLoc<<endl;
rectangle(src,minLoc,Point(minLoc.x + temp.cols,minLoc.y+temp.rows),Scalar(0,0,255),2);
// display & wait key press
cv::imshow("src", src);
cv::imshow("temp", temp);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
匹配失败,还没有找到原因。
膨胀与腐蚀
原理
- 跟卷积操作非常类似.有图像A和3x3的结构元素,结构元素在A上进行滑动。
- 计算结构元素在A上覆盖的最大像素值来替换当前结构元素对应的正中间的元素。
- 膨胀的作用:
- 对象边缘增加一个像素
- 使对象边缘平滑
- 减少了对象与对象之间的距离
代码
/**
* 膨胀的使用
*/
void testDilation() {
Mat src = imread("../img/morph-j.jpg", IMREAD_GRAYSCALE);
// 进行形态学变化
Mat dst;
// 创建结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
dilate(src, dst, kernel, Point(-1, -1), 3);
imshow("dst", dst);
imshow("src", src);
}
原理
- 腐蚀和膨胀过程类似,唯一不同的是以覆盖的最小值替换当前的像素值
- 对象边缘减少一个像素
- 对象边缘平滑
- 弱化了对象与对象之间连接
代码
/**
* 腐蚀的使用
*/
void testErode() {
Mat src = imread("../img/morph-j.jpg", IMREAD_GRAYSCALE);
// 进行形态学变化
Mat dst;
// 创建结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
erode(src, dst, kernel);
imshow("src", src);
imshow("dst", dst);
}
原理
- 先腐蚀,后膨胀,主要应用在二值图像或灰度图像
- 先腐蚀: 让当前窗口中最小的颜色值替换当前颜色值
- 后膨胀: 让当前窗口中最大的颜色值替换当前颜色值
- 作用:
- 一般用于消除小的干扰或噪点(验证码图的干扰线)
- 可以通过此操作配合结构元素,提取图像的横线和竖线
代码
/**
* 先腐蚀后膨胀
*/
void testOpening(){
Mat src = imread("../img/morph-opening.jpg",IMREAD_GRAYSCALE);
// 创建结构元素
Mat kernel = getStructuringElement(MORPH_RECT,Size(5,5));
Mat dst;
morphologyEx(src,dst,MORPH_OPEN,kernel);
imshow("dst",dst);
imshow("src",src);
}
原理
- 先膨胀,后侵蚀
- 一般用于填充内部缝隙
代码
/**
* 先膨胀后腐蚀
*/
void testClosing() {
Mat src = imread("../img/morph-closing.jpg", IMREAD_GRAYSCALE);
// 创建结构元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
// // 进行形态学变化
// Mat dilatation; // 膨胀
// dilate(src,dilatation,kernel);
//
// Mat erode_img;
// erode(dilatation,erode_img,kernel);
//
// imshow("dilatation",dilatation);
// imshow("erode_img",erode_img);
// 通用 api 进行闭操作
Mat dst;
// 通用的形态学变化
morphologyEx(src, dst, MORPH_CLOSE, kernel);
imshow("dst", dst);
imshow("src", src);
imshow("morph-closing.jpg", src);
}
链接:【OpenCV3】cv::Mat的定义与初始化
链接:OpenCV 日志写法
链接:logger.hpp File Reference
链接:Making your own linear filters!