Opencv核心功能---使用OpenCV扫描图像,查找表和时间测量

测试样例

通过使用无符号字符C和C ++类型进行矩阵项存储,像素通道可以具有多达256个不同的值。 对于三通道图像,这可以允许形成太多颜色(确切地说是1600万)。 使用如此多的色调可能会严重影响我们的算法性能。 

在这种情况下,我们通常会减少色彩空间。 这意味着我们将颜色空间当前值除以新的输入值,最终得到更少的颜色。 例如,0到9之间的每个值都取新零值,每个值在10到19之间,值为10,依此类推。

当您将uchar(unsigned char - 也就是0到255之间的值)值除以int值时,结果也将是char。 这些值可能只是char值。 因此,任何分数都将向下舍入。 利用这一事实,uchar域中的上层操作可表示为:

因此,对于较大的图像,最好事先计算所有可能的值,并在分配期间通过使用查找表进行分配。 查找表是简单数组(具有一个或多个维度),对于给定的输入值变量,它保存最终输出值。 它的优势在于我们不需要进行计算,我们只需要读取结果。

我们的测试用例程序将执行以下操作:读取控制台行参数图像(可能是颜色或灰度 - 控制台行参数)并使用给定的控制台行参数整数值应用缩减。 在OpenCV中,目前可以有三种遍历图像的方式。 为了使事情更有趣,将使用所有这些方法扫描每个图像,并打印出它花了多长时间。

下列示例的源代码下载网址:https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp

控制台的操作方式:

最后一个参数是可选的。 如果给定图像将以灰度格式加载,否则使用BGR颜色空间。 首先是计算查找表:

这里我们首先使用C ++ stringstream类将第三个命令行参数从文本转换为整数格式。 然后我们使用简单的外观和上面的公式来计算查找表。

OpenCV提供了两个简单的函数来实现这个cv :: getTickCount()和cv :: getTickFrequency()。 第一个返回特定事件(例如,自启动系统以来)系统CPU的滴答数。 第二个返回CPU在一秒钟内发出滴答的次数。 因此,要以秒为单位测量两次操作之间经过的时间很容易:

图片的矩阵在内存中如何存储

矩阵的大小取决于所使用的颜色系统。 更准确地说,它取决于使用的通道数量。 在灰度图像的情况下,我们采用下列方式:

对于多通道图像,列包含与通道数一样多的子列。 例如,在BGR颜色系统的情况下:

请注意,通道的顺序是反向的:BGR而不是RGB。 因为在许多情况下,内存足够大以便以连续方式存储行,所以行可以一个接一个地跟随,从而创建单个长行。 因为一切都在一个接一个的地方,这可能有助于加快扫描过程。 我们可以使用cv :: Mat :: isContinuous()函数来询问矩阵是否是这种情况。 

访问像素最高效的方式

我们建议的最有效的方法是:

在这里,我们基本上只获取指向每行开头的指针,然后直到它结束。 在矩阵以连续方式存储的特殊情况下,我们只需要一次请求指针并一直到最后。 我们需要注意彩色图像:我们有三个通道,所以我们需要在每行中传递三倍以上的项目。

 Mat对象的数据成员返回指向第一行第一列的指针。 如果此指针为null,则表示该对象中没有有效输入。 检查这是检查图像加载是否成功的最简单方法。 如果存储成功,我们可以使用它来遍历整个数据指针。 如果是灰度图像,这将看起来像:

访问像素最安全的访问方式

迭代器方法被认为是一种更安全的方式,因为它从用户接管这些任务。 您需要做的就是询问图像矩阵的开始和结束,然后只需增加开始迭代器直到结束。 要获取迭代器指向的值,请使用*运算符(在它之前添加它)。

在彩色图像的情况下,我们每列有三个uchar条目。 这可以被认为是uchar项目的简短向量,已经在OpenCV中使用Vec3b名称进行了修饰。 要访问第n个子列,我们使用简单的operator []访问。 重要的是要记住OpenCV迭代器遍历列并自动跳到下一行。 因此,如果使用简单的uchar迭代器,在彩色图像的情况下,您将只能访问蓝色通道值。

通过动态地址计算来访问图片

建议不要使用最终方法进行扫描。 它是为了获取或修改图像中的某些随机元素。 其基本用法是指定要访问的项目的行号和列号。

这些函数采用您的输入类型和坐标,并即时计算查询项的地址。 然后返回对它的引用。 当您获得值时,这可能是常量,而在设置值时,这可能是非常数。

如果您需要使用此方法对图像进行多次查找,则为每个访问输入类型和at关键字可能会很麻烦且耗时。 为了解决这个问题,OpenCV有一个cv :: Mat_数据类型。 它与Mat相同,需要在定义时通过查看数据矩阵来指定数据类型,您可以使用operator()来快速访问条目。 

核心函数

这是在图像中实现查找表修改的激励方法。 因为在图像处理中,您希望将所有给定图像值替换为其他值,该操作可以在不需要您编写图像扫描的情况下进行修改。 我们使用核心模块的cv :: LUT()函数。 首先,我们构建一个Mat类型的查找表:

最后调用函数(I是我们的输入图像,J是输出图像):

运行差异比较

最快的方法是LUT功能。 这是因为OpenCV库是通过Intel Threaded Building Blocks实现多线程的。 但是,如果需要编写简单的图像扫描,则更喜欢指针方法。 迭代器是一个更安全的方式,但速度相当慢。 在调试模式下,使用动态参考访问方法进行全图扫描是最昂贵的。 在发行模式下,它可能会超越迭代器方法,但它肯定会牺牲迭代器的安全特性。

猜你喜欢

转载自blog.csdn.net/LYKymy/article/details/83119622