1. 常用函数
1.1 image.row().setTo()
快捷地设置某些行、列的值可以获取某行、列的图像再调用setTo()
函数进行设置。
对于图像image:
image.row()
返回cv::Mat
,其通道数和image相同,宽高是(image.cols,1)
image.col()
返回cv::Mat
,其通道数和image相同,宽高是(1,image.rows)
image.setTo(cv::Scalar(255,255,0))
将image
设为指定的值cv::Scalar(255,255,0)
。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
for (int i = 0; i != 10; ++i)
{
img.row(i).setTo(cv::Scalar(0, 255, 255));
img.col(i).setTo(cv::Scalar(0, 255, 255));
}
for (int i = img.rows-10; i != img.rows; ++i)
{
img.row(i).setTo(cv::Scalar(0, 255, 255));
}
for (int i = img.cols - 10; i != img.cols; ++i)
{
img.col(i).setTo(cv::Scalar(0, 255, 255));
}
cv::imshow("img", img);
cv::waitKey(0);
}
效果如图1所示:
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/b7155edfa21f1c18dff3c05c4d47a586.jpeg)
1.2 图像运算
图像说白了就是普通的矩阵,可以进行加减乘除与或非等运算,再OpenCV中有相应的函数来完成这些操作,同时也重载了相应的运算符。
例如图像的加权相加:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
cv::Mat img1 = cv::imread("greed.jpg", 1);
cv::Mat img2 = cv::imread("red.jpg", 1);
cv::Mat img;
/* 使用函数进行加权相加 */
cv::addWeighted(img1, 1.0, img2, 1.0, 0., img, -1);
/* 或者使用重载运算符进行加权相加 */
// img = 1.0 * img1 + 1.0 * img2;
cv::imshow("img", img);
cv::waitKey(0);
}
其中greed.jpg:
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/d8ea9ead714b55fa0cbf8c4383c59c96.jpeg)
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/45c029f9f508b90e7c77d4a0b4ce98d2.jpeg)
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/2a6f8cc9f8e74e416bd8c11021dfbee0.jpeg)
1.3 cv::split()、cv::merge()
cv::split()
实现通道分离、cv::merge()
实现通道融合。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <vector>
int main()
{
cv::Mat img = cv::imread("ALBT9701_.jpg", 1);
cv::imshow("img", img);
std::vector<cv::Mat> planes;
cv::split(img, planes);
//cv::imshow("red-channel.jpg", planes[2]);
//cv::imshow("green-channel.jpg", planes[1]);
//cv::imshow("blue-channel.jpg", planes[0]);
cv::Mat result;
/* img与result的每个像素都是完全相同的 */
cv::merge(planes, result);
cv::imshow("result", result);
/* 求img与result的差 */
cv::Mat diff = img - result;
for (int i = 0; i != img.rows;++i)
{
cv::Vec3b *ptr = diff.ptr<cv::Vec3b>(i);
for (int j = 0; j != img.cols; ++j)
{
/* 由于diff三个通道每个像素的灰度值都是0,因此不会进入if语句块 */
if (ptr[j]!=cv::Vec3b(0,0,0))
{
std::cout << ptr[j] << std::endl;
}
}
}
cv::waitKey(0);
}
1.4 比较颜色
构建简单的算法去除图像中某种特定颜色的像素。
代码如下:
RemoveColor.h
:
#pragma once
#include <opencv2/opencv.hpp>
class RemoveColor
{
public:
RemoveColor(cv::Vec3b target,int dist);
~RemoveColor();
void setTarget(cv::Vec3b target);
cv::Vec3b getTarget();
void setMaxDist(int max_dist);
int getMaxDist();
int calcuDist(cv::Vec3b color);
cv::Mat process(cv::Mat img);
private:
cv::Vec3b m_target;
int m_max_dist;
};
RemoveColor.cpp
:
#include "RemoveColor.h"
RemoveColor::RemoveColor(cv::Vec3b target, int dist)
{
this->m_max_dist = dist;
this->m_target = target;
}
void RemoveColor::setTarget(cv::Vec3b target)
{
this->m_target = target;
}
cv::Vec3b RemoveColor::getTarget()
{
return this->m_target;
}
void RemoveColor::setMaxDist(int max_dist)
{
this->m_max_dist = max_dist;
}
int RemoveColor::getMaxDist()
{
return this->m_max_dist;
}
int RemoveColor::calcuDist(cv::Vec3b color)
{
return (abs(this->m_target[0] - color[0]) +
abs(this->m_target[1] - color[1]) +
abs(this->m_target[2] - color[2]));
}
cv::Mat RemoveColor::process(cv::Mat img)
{
cv::Mat result;
result.create(img.size(), CV_8UC1);
cv::Mat_<cv::Vec3b>::const_iterator itbeg = img.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend = img.end<cv::Vec3b>();
cv::Mat_<uchar>::iterator it_result = result.begin<uchar>();
/* 迭代器遍历img和result */
for (auto it = itbeg; it != itend; ++it, ++it_result)
{
if (calcuDist(*it) <= m_max_dist)
{
*it_result = 0;
}
else
{
*it_result = ((*it)[0] + (*it)[1] + (*it)[2])/3;
}
}
return result;
}
RemoveColor::~RemoveColor(){}
调用方法:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include "RemoveColor.h"
int main()
{
cv::Mat_<cv::Vec3b> img = cv::imread("ALBT9701_.jpg");
/* 构造 */
RemoveColor rc(cv::Vec3b(255,255,0),0);
/* 处理 */
cv::Mat result = rc.process(img);
cv::imshow("result", result);
cv::imshow("img", img);
cv::waitKey(0);
}
上面int calcuDist(cv::Vec3b color);
也可以用cv::absdiff()
,cv::sum()
来实现。举例说明这两个函数的使用方法:
cv::Vec3b result;
cv::Vec3b color(1, 2, 3);
cv::Vec3b target(11, 22, 33);
cv::absdiff(color, target, result); // result的结果是(10,20,30)
/* cv::sum()返回值是四维的,这里只需第一维 */
auto it = cv::sum(result)[0]; // it == 60
1.5 cv::floodFill()
cv::floodFill()
可以查找指定像素颜色并将其设置为目标颜色,该函数会将指定的某个像素位置周围的连续区域都进行判断。例如:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
int main()
{
cv::Mat_<cv::Vec3b> img = cv::imread("ALBT9701__.jpg");
cv::floodFill(img, cv::Point(550, 250), cv::Scalar(255, 0, 0),
(cv::Rect*)0, cv::Scalar(35, 35, 35), cv::Scalar(35, 35, 35),
cv::FLOODFILL_FIXED_RANGE);
cv::imshow("img", img);
cv::waitKey(0);
}
图5是输入图像,图6是处理后的效果。坐标(500,250)
处于颜色(255,255,0)
大矩形位置,可以看到整个大矩形被重置了颜色,而小矩形不变。
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/f416d4ee9fd379cc08d373b1ce3dec79.jpeg)
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/ff1db925f566eb20ac11408f05f8f1a1.jpeg)
1.6 行列式相乘[线性代数]
OpenCV中行列式相乘要求两个矩阵数据类型必须相同,且数据类型是CV_32FC1、 CV_64FC1、 CV_32FC2、 CV_64FC2之一。
相乘与顺序有关,这点与行列式乘法规则一样。ab与ba是完全不同的。
/* OpenCV行列式相乘,通道1*通道1 - 通道2*通道2 = 通道1
通道1*通道2 + 通道2*通道1 = 通道2*/
#include <cv.h>
#include <highgui.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main()
{
cv::Mat a(2, 3, CV_32FC2);
cv::Mat b(3, 2, CV_32FC2);
cv::Mat img(2, 2, CV_32FC2);
for (int i = 0; i != 2; ++i)
{
for (int j = 0; j != 3; ++j)
{
a.at<cv::Vec2f>(i, j) = cv::Vec2f(i + j, 1);
}
}
int count = 0;
for (int i = 0; i != 3; ++i)
{
for (int j = 0; j != 2; ++j)
{
b.at<cv::Vec2f>(i, j) = cv::Vec2f(++count, 1);
}
}
img = a*b;
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
图7是相乘结果示意图:
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/a82b3e8b9f3d068f4d53ed4d1819a921.jpeg)
1.7 随机颜色
#include <ctime>
#include "opencv2/core/core.hpp"
cv::RNG rng((unsigned)time(NULL));
auto color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
1.8 opencv读入数据是1*H*W*C
的形式
在跟深度学习相关的任务中要注意opencv通过imread进来的图片是1*H*W*C
形式的。
2. cmake选项
参考OpenCV configuration options reference
例如:
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.x/modules -DWITH_IPP=OFF -DBUILD_JAVA=OFF -DBUILD_opencv_java_bindings_generator=OFF -DBUILD_opencv_world=ON -DBUILD_opencv_python_tests=OFF -DWITH_ADE=OFF -DWITH_VTK=OFF -DWITH_CUDA=OFF ../opencv-4.x/
支持CUDA:
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=OFF -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.x/modules -DWITH_IPP=OFF -DBUILD_JAVA=OFF -DBUILD_opencv_java_bindings_generator=OFF -DBUILD_opencv_world=ON -DBUILD_opencv_python_tests=OFF -DWITH_ADE=OFF -DWITH_VTK=OFF -DWITH_CUDA=ON ../opencv-4.x/
不管cmake指定的是什么generator都可以使用如下指令编译、安装(安装好之后即可使用安装路径下的头文件、库文件)
cmake --build . --config Release
cmake --install . --config Release --prefix "/home/opencv"
关于install请参考:https://cmake.org/cmake/help/latest/guide/tutorial/Installing%20and%20Testing.html
2.1 Xcode
如果generator是Xcode需要在cmake参数或者CMakeList.txt中指明工具链,可能也要在CMakeList.txt中指明要支持C++11(否则可能有报错:error "OpenCV 4.x+ requires enabled C++11 support"
)。
下面指令可能有些问题,建议在CMake-GUI上configure, Generate完之后,在Xcode上编译:
cmake -G Xcode -DCMAKE_C_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -DCMAKE_CXX_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.x/modules -DWITH_IPP=OFF -DBUILD_JAVA=OFF -DBUILD_opencv_java_bindings_generator=OFF -DBUILD_opencv_world=ON -DBUILD_opencv_python_tests=OFF -DWITH_ADE=OFF -DWITH_VTK=OFF ../opencv-4.x/
或在CMakeList.txt文件开头加上:
set (CMAKE_C_COMPILER "/usr/local/gcc/bin/gcc")
set (CMAKE_CXX_COMPILER "/usr/local/gcc/bin/g++")
set(CMAKE_CXX_STANDARD 11) # 指定C++标准
在Xcode的菜单Product->Scheme->Edit Scheme...
中配置生成Debug还是Release库。
在Xcode上使用库时注意有三个地方的路径需要配置:头文件搜索路径、库文件搜索路径、运行时库文件链接路径
2.2 Apple M1 Max有点垃圾
Apple M1 Max,macOS Monterey 版本12.6
编译完opencv后使用编译库的时候提示:
![ellipse](https://i-blog.csdnimg.cn/blog_migrate/23851079a65d78d528a040f0dac8a511.jpeg)
尝试过很多方法,均未解决:
https://juejin.cn/post/7108730107056881700
https://sayak.dev/install-opencv-m1/
http://events.jianshu.io/p/ac8121d0c51f
https://cloud.tencent.com/developer/ask/sof/1175046/answer/1636270
最终解决方法是用cmake-gui生成Xcode工程,让后在Xcode工程编译OpenCV库。
使用编译的OpenCV库时要用Xcode建立工程,导入编译的OpenCV库。如果不使用Xcode可能还是会有各种问题。总之Apple M1 Max芯片垃圾的一塌糊涂!!!
#if __cplusplus < 201103L
#error "should use C++11 implmentation"
#endif