0.功能
??????? 使用形态学操作morphological operations提取出图像中水平线和数值线horizontal and vertical lines,即分别让图像的水平部分或竖直部分更凸显出来
1.工作空间准备
??????? 为了使这个单一的cpp文件能够执行,进行如下操作.
mkdir -p opencv_hv/src
cd opencv_hv/src
catkin_create_pkg image_proc std_msgs roscpp rospy cv_bridge
cd ../..
gedit hv.launch
??????? 在hv.launch文件中粘贴下述代码段,保存并关闭
<launch>
<node pkg="image_processing" type="horizontal_and_vertical_line_node" name="horizontal_and_vertical_line" output="screen" />
</launch>
???????? 工作空间结构如下:
# meng @ meng in ~/opencv_hv [22:28:30]
$ tree
.
├── hv.launch
└── src
└── image_proc
├── CMakeLists.txt
├── include
│?? └── image_proc
├── package.xml
└── src
5 directories, 3 files
2.程序准备与解读
????????在/home/meng/opencv_hv/src/image_proc/src 文件夹下添加如下文件: ?horizontal_and_vertical_line_node.cpp
// Extract horizontal and vertical lines by using morphological operations
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
void show_wait_destroy(const char* winname, cv::Mat img);
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
/*CommandLineParser parser(argc, argv, "{@input | notes.png | input image}");
Mat src = imread( samples::findFile( parser.get<String>("@input") ), IMREAD_COLOR);
官方示例是这两行,使用起来相对麻烦,这里改为下面这一行*/
Mat src = imread( "/home/meng/my_learning/opencv_test/src/image_processing/src/note.png", IMREAD_COLOR);//彩色图像
if (src.empty())
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
// Show source image
imshow("src", src);
// Transform source image to gray if it is not already
Mat gray;
if (src.channels() == 3)//如果为3通道
{ //BGR彩色转为灰度图,这是为了方便下面处理
cvtColor(src, gray, COLOR_BGR2GRAY);
}
else
{
gray = src;
}
// Show gray image
show_wait_destroy("gray", gray);
// Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbol
Mat bw;
/*adaptiveThreshold:自适应阈值函数
~gray, bw: ~按位不,源图像和目标图像 255:maxValue最大值
ADAPTIVE_THRESH_MEAN_C:(x,y):每个位置像素值的阈值,邻域blockSize*blockSize范围内的均值再减去C的值
thresholdType:阈值类型,这里每个位置处的像素值大于相应阈值则该位置处设为maxValue
15:blockSize的值 -2:C值
下面使原来"亮"的地方更暗,"暗"的地方更亮
*/
adaptiveThreshold(~gray, bw, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
// Show binary image
show_wait_destroy("binary", bw);
// Create the images that will use to extract the horizontal and vertical lines 提取水平和竖值线
Mat horizontal = bw.clone();
Mat vertical = bw.clone();
// Specify size on horizontal axis
int horizontal_size = horizontal.cols / 30;
// Create structure element for extracting horizontal lines through morphology operations
//构建结构单元:形状及大小
Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontal_size, 1));
// Apply morphology operations
erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));
// Show extracted horizontal lines
show_wait_destroy("horizontal", horizontal);
// Specify size on vertical axis
int vertical_size = vertical.rows / 30;
// Create structure element for extracting vertical lines through morphology operations
Mat verticalStructure = getStructuringElement(MORPH_RECT, Size(1, vertical_size));
// Apply morphology operations
erode(vertical, vertical, verticalStructure, Point(-1, -1));
dilate(vertical, vertical, verticalStructure, Point(-1, -1));
// Show extracted vertical lines
show_wait_destroy("vertical", vertical);
// Inverse vertical image
bitwise_not(vertical, vertical);
show_wait_destroy("vertical_bit", vertical);
// Extract edges and smooth image according to the logic
// 1. extract edges
// 2. dilate(edges)
// 3. src.copyTo(smooth)
// 4. blur smooth img
// 5. smooth.copyTo(src, edges)
// Step 1 获取高亮区域边缘
Mat edges;
adaptiveThreshold(vertical, edges, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
show_wait_destroy("edges", edges);
// Step 2 使高亮区域边缘更明显
Mat kernel = Mat::ones(2, 2, CV_8UC1);
dilate(edges, edges, kernel);
show_wait_destroy("dilate", edges);
// Step 3
Mat smooth;
vertical.copyTo(smooth);//把vertical内容复制到smooth上
show_wait_destroy("smooth_3", smooth);
// Step 4 平滑滤波
blur(smooth, smooth, Size(2, 2));
show_wait_destroy("smooth_4", smooth);
// Step 5 函数:image.copyTo(imageROI,mask)
//作用是把mask和image重叠以后把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。
smooth.copyTo(vertical, edges);
// Show final result
show_wait_destroy("smooth - final", vertical);
return 0;
}
void show_wait_destroy(const char* winname, cv::Mat img) {
imshow(winname, img);
moveWindow(winname, 500, 0);
waitKey(0);
destroyWindow(winname);
}
??????? 同时修改/home/meng/opencv_hv/src/image_proc/CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.0.2)
project(image_processing)
find_package(catkin REQUIRED COMPONENTS
cv_bridge
roscpp
rospy
std_msgs
)
find_package(OpenCV REQUIRED)
catkin_package()
include_directories(
# include
${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}
)
add_executable(horizontal_and_vertical_line_node src/horizontal_and_vertical_line_node.cpp)
target_link_libraries(horizontal_and_vertical_line_node
${catkin_LIBRARIES} ${OpenCV_LIBS}
)
3.程序运行????????
????????回到:/home/meng/opencv_hv,
????????效果如图
catkin_make
source devel/setup.bash
#或source devel/setup.zsh
roslaunch hv.launch
src
gray
binary
horizontal
vertical
vertical_blt
edge
somth_final
参考链接:
(1).adaptiveThreshold():https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3
(2):https://docs.opencv.org/master/dd/dd7/tutorial_morph_lines_detection.html
|