OpenCV代码提取:dilate函数的实现

2023-11-16

Morphological Operations: A set of operations that process images based on shapes.Morphological operations apply a structuring element to an input image and generate an output image.

The most basic morphological operations are two: Erosion and Dilation. They have a wide array of uses, i.e.:

(1)、Removing noise.

(2)、Isolation of individual elements and joining disparate elements in an image.

(3)、Finding of intensity bumps or holes in an image.

数学形态学可以理解为一种滤波行为,因此也称为形态学滤波。滤波中用到的滤波器(kernal),在形态学中称为结构元素。结构元素往往是由一个特殊的形状构成,如线条、矩形、圆等。

OpenCV中的dilate函数支持多通道,各个通道膨胀处理过程独立。膨胀针对白色部分(高亮部分)。膨胀即是求局部最大值的操作,图像A与核B作卷积运算,计算核B覆盖区域的像素点的最大值,并把这个值赋值给锚点(anchor point)指定的像素。

Dilation:

(1)、This operations consists of convoluting an image A with some kernel(B), which can have any shape or size, usually a square or circle.

(2)、The kernel B has a defined anchor point, usually being the center of the kernel.

(3)、As the kernel B is scanned over the image, we compute the maximal pixel value overlapped by B and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to “grow” (therefore the name dilation).


目前fbc_cv库中支持uchar和float两种数据类型,经测试,与OpenCV3.1结果完全一致。

实现代码dilate.cpp:

// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com

#ifndef FBC_CV_DILATE_HPP_
#define FBC_CV_DILATE_HPP_

/* reference: include/opencv2/imgproc.hpp
              modules/imgproc/src/morph.cpp
*/

#include <typeinfo>
#include "core/mat.hpp"
#include "imgproc.hpp"
#include "filterengine.hpp"
#include "core/core.hpp"
#include "morph.hpp"

namespace fbc {

// Dilates an image by using a specific structuring element
// \f[\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
// In case of multi - channel images, each channel is processed independently.
// support type: uchar/float, multi-channels
template<typename _Tp, int chs>
int dilate(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, Mat_<uchar, 1>& kernel,
	Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = Scalar::all(DBL_MAX))
{
	FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
	if (dst.empty()) {
		dst = Mat_<_Tp, chs>(src.rows, src.cols);
	} else {
		FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);
	}

	Size ksize = !kernel.empty() ? kernel.size() : Size(3, 3);
	anchor = normalizeAnchor(anchor, ksize);

	if (iterations == 0 || kernel.rows * kernel.cols == 1) {
		src.copyTo(dst);
		return 0;
	}

	if (kernel.empty()) {
		kernel = Mat_<uchar, 1>(1 + iterations * 2, 1 + iterations * 2);
		getStructuringElement(kernel, MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2));
		anchor = Point(iterations, iterations);
		iterations = 1;
	} else if (iterations > 1 && countNonZero(kernel) == kernel.rows * kernel.cols) {
		anchor = Point(anchor.x*iterations, anchor.y*iterations);
		kernel = Mat_<uchar, 1>(ksize.height + (iterations - 1)*(ksize.height - 1), ksize.width + (iterations - 1)*(ksize.width - 1));
		getStructuringElement(kernel, MORPH_RECT,
			Size(ksize.width + (iterations - 1)*(ksize.width - 1), ksize.height + (iterations - 1)*(ksize.height - 1)), anchor);
		iterations = 1;
	}

	anchor = normalizeAnchor(anchor, kernel.size());

	Ptr<BaseRowFilter> rowFilter;
	Ptr<BaseColumnFilter> columnFilter;
	Ptr<BaseFilter> filter2D;

	if (countNonZero(kernel) == kernel.rows*kernel.cols) {
		// rectangular structuring element
		rowFilter = getMorphologyRowFilter<_Tp, chs>(1, kernel.cols, anchor.x);
		columnFilter = getMorphologyColumnFilter<_Tp, chs>(1, kernel.rows, anchor.y);
	} else {
		filter2D = getMorphologyFilter<_Tp, chs>(1, kernel, anchor);
	}

	Scalar borderValue_ = borderValue;
	if (borderType == BORDER_CONSTANT && borderValue_ == Scalar::all(DBL_MAX)) {
		if (sizeof(_Tp) == 1) // CV_8U
			borderValue_ = Scalar::all(0.);
		else // CV_32F
			borderValue_ = Scalar::all(-FLT_MAX);
	}

	Ptr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>> f = makePtr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>>(filter2D, rowFilter, columnFilter, borderType, borderType, borderValue_);
	f->apply(src, dst);
	for (int i = 1; i < iterations; i++)
		f->apply(dst, dst);

	return 0;
}

} // namespace fbc

#endif // FBC_CV_DILATE_HPP_

测试代码test_dilate.cpp:

#include "test_dilate.hpp"
#include <assert.h>

#include <dilate.hpp>
#include <opencv2/opencv.hpp>

int test_getStructuringElement()
{
	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 10; size++) {
			int type;
			if (elem == 0){ type = fbc::MORPH_RECT; }
			else if (elem == 1){ type = fbc::MORPH_CROSS; }
			else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

			fbc::Mat_<uchar, 1> element(2*size+1, 2*size+1);
			fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

			int type_;
			if (elem == 0){ type_ = cv::MORPH_RECT; }
			else if (elem == 1){ type_ = cv::MORPH_CROSS; }
			else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

			cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

			assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
			for (int y = 0; y < element.rows; y++) {
				const fbc::uchar* p1 = element.ptr(y);
				const uchar* p2 = element_.ptr(y);

				for (int x = 0; x < element.step; x++) {
					assert(p1[x] == p2[x]);
					if (size == 5)
						fprintf(stderr, "%d  ", p1[x]);
				}
				if (size == 5)
					fprintf(stderr, "\n");
			}

			if (size == 5)
				fprintf(stderr, "\n");
		}
	}

	return 0;
}

int test_dilate_uchar()
{
	cv::Mat matSrc = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	if (!matSrc.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}

	int width = matSrc.cols;
	int height = matSrc.rows;

	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 10; size++) {
			for (int iterations = 1; iterations < 5; iterations++) {
				int type;
				if (elem == 0){ type = fbc::MORPH_RECT; }
				else if (elem == 1){ type = fbc::MORPH_CROSS; }
				else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

				fbc::Mat_<uchar, 1> element(2 * size + 1, 2 * size + 1);
				fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

				int type_;
				if (elem == 0){ type_ = cv::MORPH_RECT; }
				else if (elem == 1){ type_ = cv::MORPH_CROSS; }
				else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

				cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

				assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
				for (int y = 0; y < element.rows; y++) {
					const fbc::uchar* p1 = element.ptr(y);
					const uchar* p2 = element_.ptr(y);

					for (int x = 0; x < element.step; x++) {
						assert(p1[x] == p2[x]);
					}
				}

				fbc::Mat3BGR mat1(height, width, matSrc.data);
				fbc::Mat3BGR mat2(height, width);
				fbc::dilate(mat1, mat2, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

				cv::Mat mat1_(height, width, CV_8UC3, matSrc.data);
				cv::Mat mat2_;
				cv::dilate(mat1_, mat2_, element_, cv::Point(-1, -1), iterations, 0, cv::Scalar::all(128));

				assert(mat2.rows == mat2_.rows && mat2.cols == mat2_.cols && mat2.step == mat2_.step);
				for (int y = 0; y < mat2.rows; y++) {
					const fbc::uchar* p1 = mat2.ptr(y);
					const uchar* p2 = mat2_.ptr(y);

					for (int x = 0; x < mat2.step; x++) {
						assert(p1[x] == p2[x]);
					}
				}
			}
		}
	}

	return 0;
}

int test_dilate_float()
{
	cv::Mat matSrc = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	if (!matSrc.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}
	cv::cvtColor(matSrc, matSrc, CV_BGR2GRAY);
	matSrc.convertTo(matSrc, CV_32FC1);

	int width = matSrc.cols;
	int height = matSrc.rows;

	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 10; size++) {
			for (int iterations = 1; iterations < 5; iterations++) {
				int type;
				if (elem == 0){ type = fbc::MORPH_RECT; }
				else if (elem == 1){ type = fbc::MORPH_CROSS; }
				else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

				fbc::Mat_<uchar, 1> element(2 * size + 1, 2 * size + 1);
				fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

				int type_;
				if (elem == 0){ type_ = cv::MORPH_RECT; }
				else if (elem == 1){ type_ = cv::MORPH_CROSS; }
				else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

				cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

				assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
				for (int y = 0; y < element.rows; y++) {
					const fbc::uchar* p1 = element.ptr(y);
					const uchar* p2 = element_.ptr(y);

					for (int x = 0; x < element.step; x++) {
						assert(p1[x] == p2[x]);
					}
				}

				fbc::Mat_<float, 1> mat1(height, width, matSrc.data);
				fbc::Mat_<float, 1> mat2(height, width);
				fbc::dilate(mat1, mat2, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

				cv::Mat mat1_(height, width, CV_32FC1, matSrc.data);
				cv::Mat mat2_;
				cv::dilate(mat1_, mat2_, element_, cv::Point(-1, -1), iterations, 0, cv::Scalar::all(128));

				assert(mat2.rows == mat2_.rows && mat2.cols == mat2_.cols && mat2.step == mat2_.step);
				for (int y = 0; y < mat2.rows; y++) {
					const fbc::uchar* p1 = mat2.ptr(y);
					const uchar* p2 = mat2_.ptr(y);

					for (int x = 0; x < mat2.step; x++) {
						assert(p1[x] == p2[x]);
					}
				}
			}
		}
	}

	return 0;
}

GitHubhttps://github.com/fengbingchun/OpenCV_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV代码提取:dilate函数的实现 的相关文章

  • CvMat 和 Imread 与 IpImage 和 CvLoadImage

    使用 OpenCv 2 4 我有两个选项来加载图像 1 CvMat and Imread 2 IpImage and CvLoadImage 使用哪一个更好 我尝试将两者混合并最终出现段错误 imread返回一个Mat not CvMat
  • 查找彼此接近的对象边界

    我正在研究一个计算机视觉问题 其中问题的第一步是找到物体彼此靠近的位置 例如 在下图中 我感兴趣的是找到灰色标记的区域 Input Output 我目前的方法是首先反转图像 然后通过侵蚀进行形态梯度跟随 然后删除一些不感兴趣的轮廓 脚本如下
  • 计算两个描述符之间的距离

    我正在尝试计算已计算的两个描述符之间的距离 欧几里得或汉明 问题是我不想使用匹配器 我只想计算两个描述符之间的距离 我正在使用 OpenCV 2 4 9 并且我的描述符存储在 Mat 类型中 Mat descriptors1 Mat des
  • opencv中矩阵的超快中值(与matlab一样快)

    我正在 openCV 中编写一些代码 想要找到一个非常大的矩阵数组 单通道灰度 浮点数 的中值 我尝试了几种方法 例如对数组进行排序 使用 std sort 和选择中间条目 但与 matlab 中的中值函数相比 它非常慢 准确地说 在 ma
  • OpenCV:视频结束后如何重新启动?

    我正在播放视频文件 但播放完毕后如何再次播放 Javier 如果您想一遍又一遍地重新启动视频 也称为循环播放 可以通过在帧数达到时使用 if 语句来实现cap get cv2 cv CV CAP PROP FRAME COUNT 然后重置帧
  • 如何计算图像中的 RGB 或 HSV 通道组合?

    我使用 python opencv 加载形状为 30 100 3 的图像 现在想要按颜色计算所有颜色的频率 我不是指单个通道 而是指通道组合 含义 3 个频道列表 例如 255 0 0 表示红色 255 255 0 表示黄色 100 100
  • 我可以使用 openCV 比较两张不同图像上的两张脸吗?

    我对 openCV 很陌生 我看到它可以计算出脸部并返回一个矩形来指示脸部 我想知道 openCV 是否可以访问两张包含一张脸的图像 并且我希望 openCV 返回这两个人是否相同的可能性 Thanks OpenCV 不提供完整的人脸识别引
  • 如何将 mat 转换为 array2d

    我为dlib http dlib net face landmark detection ex cpp html那里的面部地标代码使用 array2d 来获取图像 但我喜欢使用 Mat 读取图像并转换为 array2d 因为 dlib 仅支
  • OpenCV 仅围绕大轮廓绘制矩形?

    第一次发帖 希望我以正确的方式放置代码 我正在尝试检测和计算视频中的车辆 因此 如果您查看下面的代码 我会在阈值处理和膨胀后找到图像的轮廓 然后我使用 drawContours 和矩形在检测到的轮廓周围绘制一个框 我试图在 drawCont
  • OpenCV 3 中的 FLANN 错误

    我运行的是 Ubuntu 14 04 我正在尝试使用 openCV 3 运行 FLANN 但出现错误 下面的所有内容都是通过使用 AKAZE 和 ORB 进行尝试的 但代码来自我尝试使用 ORB 的情况 我使用 ORB 来查找描述符和关键点
  • opencv 2.3.* 读取不工作

    我无法让 imread 工作 与这个人有同样的问题 OpenCV imwrite 2 2 在 Windows 7 上导致异常 并显示消息 OpenCV 错误 未指定错误 无法找到指定扩展名的编写器 https stackoverflow c
  • 当我将鼠标移到 Mat 关键字上时,Visual Studio 2017 冻结(OpenCv 3.4.1)

    我想在 Visual Studio 2017 中开发 openCv 项目 我下载了 opencv 预构建库并进行了必要的设置 那是 1 我添加了系统路径 build x64 vc14 bin 2 在 Visual Studio 中的项目属性
  • OpenCV Visual Studio ntdll.dll

    我尝试在 Visual Studio 2013 上使用 OpenCV 2 4 10 创建一个项目 但由于以下异常 到目前为止我运气不佳 请建议帮助 TIA letstryitonemoretime exe Win32 Loaded C Us
  • 检查图像中是否有太薄的区域

    我正在尝试验证雕刻机的黑白图像 更多的是剪贴画图像 不是照片 我需要考虑的主要事情之一是区域的大小 或线条的宽度 因为机器无法处理太细的线条 所以我需要找到比给定阈值更细的区域 以此图为例 竖琴的琴弦可能太细而无法雕刻 我正在阅读有关 Ma
  • 为什么我无法在 Mac 12.0.1 (Monterey) 上使用 pip 安装 OpenCV? [复制]

    这个问题在这里已经有答案了 当我尝试使用 python pip 安装 OpenCV 时 它显示了以下内容 Remainder of file ignored Requirement already satisfied pip in Libr
  • OpenCV 错误:connectedComponents_sub1 中断言失败 (L.channels() == 1 && I.channels() == 1) [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我在 OpenCV python 中遇到以下错误 并用 google 搜索了很多 但无法解决 如果有人能为我提供一些线索
  • 从包含带边框的表格的图像中提取表格结构

    我正在尝试提取下表中的单元格位置 应用自适应阈值处理后 我能够获得细胞位置周围的轮廓 并且 HoughLines 获得垂直和水平结构元素 这是我的代码 img cv2 imread os path join img path file im
  • 2d 图像点和 3d 网格之间的交点

    Given 网格 源相机 我有内在和外在参数 图像坐标 2d Output 3D 点 是从相机中心发出的光线穿过图像平面上的 2d 点与网格的交点 我试图找到网格上的 3d 点 This is the process From Multip
  • 如何使用 opencv python 计算乐高积木上的孔数?

    我正在开发我的 python 项目 我需要计算每个乐高积木组件中有多少个孔 我将从输入 json 文件中获取有关需要计算哪个程序集的信息 如下所示 img 001 red 0 blue 2 white 1 grey 1 yellow 1 r
  • 同时从多个流中捕获、最佳方法以及如何减少 CPU 使用率

    我目前正在编写一个应用程序 该应用程序将捕获大量 RTSP 流 在我的例子中为 12 个 并将其显示在 QT 小部件上 当我超过大约 6 7 个流时 问题就会出现 CPU 使用率激增并且出现明显的卡顿 我认为它不是 QT 绘制函数的原因是因

随机推荐

  • 详解3D中obj文件格式

    原文链接 https www jianshu com p f7f3e7b6ebf5 加载3D模型的时候 遇到 obj格式的模型文件 之前有专门看过相关的资料 可惜没有总结 一下就忘了 再次用到 又去搜索了一番 发现网上很多文章讲的不是很全面
  • Char和VarChar的区别(无废话版)

    区别1 定长与变长 char表示定长 长度固定 varchar表示变长 即长度可变 char如果插入的长度小于自定义长度时候 中间用空格填充 varChar小于定义长度时 还是按照实际长度存储 插入多长就存多长 因为长度是固定的 char的
  • 浙江农林大学蓝桥杯程序设计竞赛校选拔赛 E-谁是天选之人

    众所周知下棋是一个运气游戏 不过好像也是有规律可循的 Graceful smiling cookies给它的n个棋子标序号 他决定以这些序号决定谁是天选 最开始每个棋子标号都是0 它要进行m次标序号 第i次标序号 它会将第 i X a b
  • python decimal 转换为float_在Python中将float转换为decimal类型

    我只是在玩数字游戏 我发现Numpy提供了一个名为np vectorize的函数 允许您获取一个函数并将其应用于Numpy数组 在 23 中 import numpy as np import decimal D decimal Decim
  • manjaro笔记本显卡驱动_从入门到高端!AMD Radeon RX 500系列移动显卡全解析

    前言 在处理器领域 卧薪尝胆十年之久的AMD终究还是给所有玩家带来了惊喜 2017年2月推出了ZEN构架的处理器之后 相信后面的事情大家都知道了 手忙脚乱的Intel公司在不到2年的时间内连续发布了三代酷睿产品以应对Ryzen处理器的威胁
  • mysql5.7以上的启动、停止、赋权命令

    文章目录 1 启动mysql server 2 查看初始密码 3 本地登陆mysql 4 修改本地root用户密码 5 防火墙设置 6 开启mysql的远程登录 1 启动mysql server systemctl start mysqld
  • 查看数据库字符集

    问题描述 最近发现在不同的数据库中 有时中文占用2个字节 有时占用3个字节 经过分析发现 对于varchar类型的字段 如果数据库字符集使用utf 8 则3个字节表示一个中文 如果数据库字符集使用gbk 则2个字节表示一个中文 数据库字符集
  • QMainWindow、QDialog与QWidget的区别

    一 定义 QWidget 是所有用户界面对象的基类 窗口部件是用户界面的一个原子 它从窗口系统接收鼠标 键盘和其它事件 并且在屏幕上绘制自己的表现 每一个窗口部件都是矩形 并且它们按Z轴顺序排列的 一个窗口部件可以被它的父窗口部件或者它前面
  • 关于mysql导入中文乱码问题的理解

    一般来说 mysql导入方式有三种 一种是通过mysql命令导入 一种是通过source方式导入 最后一种是直接复制sql语句导入 前两种方式一般都能导入成功 但如果这个备份文件有问题 例如本身这个文件里面在默认编码下就乱码了 那么第三种方
  • 全连接层详解

    一 什么是全连接层 转载自 https blog csdn net qq 39521554 article details 81385159 全连接层 fully connected layers FC 在整个卷积神经网络中起到 分类器 的
  • Hyperledger Fabric 应用实战(2)--网络节点设置

    1 网络节点设置 网络名称 rentnet 联盟组织 orderer排序组织 三个成员组织supervisor rentalcrop agency 通道 rentsign 账本数据库 couchdb 物理节点 组织 容器节点 supervi
  • 普通代码块,静态代码块,构造代码块,构造方法

    1 使用示例 2 静态代码块介绍 在类中通过static修饰然后大括号里面的内容就是静态代码块 见13 1实例 static 静态代码块在类被加载的时候执行 并且他只会执行一次 优先于其他所有代码块以及构造方法执行 如果有多个静态代码块则按
  • 怎么用电脑兼职赚钱,普通人可做的6个副业项目

    现在的生活中 我们总是感觉所过的日子都很紧张 虽然我们尽可能地工作和努力 但是生活成本和社会压力仍然那么大 为了弥补自己的生活经验和财务困难 很多人开始寻找一种额外的收入来源 其实这种额外的收入来源就被称之为 兼职或副业 在如今的经济环境中
  • 浅析数组名与&数组名的区别

    一 一维数组 我们借助sizeof帮助我们理解 运行结果如下 二 二维数组 同样借助sizeof来理解 运行结果如下 三 字符型数组 1 借助sizeof来理解 类似的 注意 a b数组有一些差别 造成这种差别的原因是b数组是字符串赋值 此
  • Liveness、Readiness 和 Startup Probes

    liveness apiVersion v1 kind Pod metadata labels test liveness name liveness exec spec containers name liveness image k8s
  • tomcat点击startup.bat一闪而退的解决方法

    1 点击startup bat会闪退 编辑startup bat 在最后一行加入pause 然后保存 再次运行 就可以看到闪退的原因 2 出现这个的原因是没有配置启动的环境JAVA HOME 下面配置一下JAVA HOME 右键电脑 点击属
  • mysql数据库优化--分区

    前言 公司业务数据量很大 因为是面向全国的数据统计分析 所以一天大约是大几十万数据 因为最开始设计架构没有参与 当系统出现问题 去查看的时候发现数据库两个表一个三亿多 另一个十一亿 1 优化思路 因为单表破亿执行sql现在都是问题了 del
  • sudo apt-get update 报错(Ubuntu20.04)

    1 错误 今天运行 sudo apt get update 时报错 appstreamcli 10947 GLib ERROR 09 43 36 719 g variant new parsed 11 13 invalid GVariant
  • 分巧克力 蓝桥杯 99

    题目描述 儿童节那天有 K 位小朋友到小明家做客 小明拿出了珍藏的巧克力招待小朋友们 小明一共有 N 块巧克力 其中第 i 块是 Hi Wi 的方格组成的长方形 为了公平起见 小明需要从这N 块巧克力中切出 K 块巧克力分给小朋友们 切出的
  • OpenCV代码提取:dilate函数的实现

    Morphological Operations A set of operations that process images based on shapes Morphological operations apply a struct