OpenCV tips

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
图1 image.row().setTo()

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
图2 greed.jpg
red.jpg:
ellipse
图3 red.jpg
加权相加的效果是:
ellipse
图4 cv::addWeighted()-->yellow
还有许多其它的运算函数、重载的运算符。

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
图5 输入图像
ellipse
图6 效果

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
图7 行列式相乘

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
图8 Apple M1 Max Undefined symbols for architecture arm64

尝试过很多方法,均未解决:
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
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值