OpenCV中实现图像翻转的函数flip,公式为:

目前fbc_cv库中也实现了flip函数,支持多通道,uchar和float两种数据类型,经测试,与OpenCV3.1结果完全一致。

实现代码flip.hpp:

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

#ifndef FBC_CV_FLIP_HPP_
#define FBC_CV_FLIP_HPP_

/* reference: include/opencv2/core.hpp
              modules/core/src/copy.cpp
*/

#include <typeinfo>
#include "core/mat.hpp"

namespace fbc {

template<typename _Tp, int chs> static int flipHoriz(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);
template<typename _Tp, int chs> static int flipVert(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);

// Flips a 2D array around vertical, horizontal, or both axes
// flipCode: 0 means flipping around the x - axis and positive value means flipping around y - axis.
//	     Negative value means flipping around both axes
// support type: uchar/float, multi-channels
template <typename _Tp, int chs>
int flip(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int flipCode)
{
	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 size = src.size();

	if (flipCode < 0) {
		if (size.width == 1)
			flipCode = 0;
		if (size.height == 1)
			flipCode = 1;
	}

	if ((size.width == 1 && flipCode > 0) ||
		(size.height == 1 && flipCode == 0) ||
		(size.height == 1 && size.width == 1 && flipCode < 0)) {
		src.copyTo(dst);
		return 0;
	}

	if (flipCode <= 0)
		flipVert(src, dst);
	else
		flipHoriz(src, dst);

	if (flipCode < 0)
		flipHoriz(dst, dst);

	return 0;
}

template<typename _Tp, int chs>
static int flipHoriz(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
	Size size = src.size();
	size_t esz = sizeof(_Tp) * chs;
	int i, j, limit = (int)(((size.width + 1) / 2) *esz );
	AutoBuffer<int> _tab(size.width * esz);
	int* tab = _tab;
	size_t sstep = src.step;
	size_t dstep = dst.step;
	const uchar* src_ = src.ptr();
	uchar* dst_ = dst.ptr();

	for (i = 0; i < size.width; i++) {
		for (size_t k = 0; k < esz; k++) {
			tab[i*esz + k] = (int)((size.width - i - 1) * esz + k);
		}
	}

	for (; size.height--; src_ += sstep, dst_ += dstep) {
		for (i = 0; i < limit; i++) {
			j = tab[i];
			uchar t0 = src_[i], t1 = src_[j];
			dst_[i] = t1; dst_[j] = t0;
		}
	}

	return 0;
}

template<typename _Tp, int chs>
static int flipVert(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
	const uchar* src0 = src.ptr();
	uchar* dst0 = dst.ptr();
	Size size = src.size();
	size_t sstep = src.step;
	size_t dstep = dst.step;
	size_t esz = sizeof(_Tp) * chs;
	const uchar* src1 = src0 + (size.height - 1)*sstep;
	uchar* dst1 = dst0 + (size.height - 1)*dstep;
	size.width *= (int)esz;

	for (int y = 0; y < (size.height + 1) / 2; y++, src0 += sstep, src1 -= sstep, dst0 += dstep, dst1 -= dstep) {
		int i = 0;
		if (((size_t)src0 | (size_t)dst0 | (size_t)src1 | (size_t)dst1) % sizeof(int) == 0) {
			for (; i <= size.width - 16; i += 16) {
				int t0 = ((int*)(src0 + i))[0];
				int t1 = ((int*)(src1 + i))[0];

				((int*)(dst0 + i))[0] = t1;
				((int*)(dst1 + i))[0] = t0;

				t0 = ((int*)(src0 + i))[1];
				t1 = ((int*)(src1 + i))[1];

				((int*)(dst0 + i))[1] = t1;
				((int*)(dst1 + i))[1] = t0;

				t0 = ((int*)(src0 + i))[2];
				t1 = ((int*)(src1 + i))[2];

				((int*)(dst0 + i))[2] = t1;
				((int*)(dst1 + i))[2] = t0;

				t0 = ((int*)(src0 + i))[3];
				t1 = ((int*)(src1 + i))[3];

				((int*)(dst0 + i))[3] = t1;
				((int*)(dst1 + i))[3] = t0;
			}

			for (; i <= size.width - 4; i += 4) {
				int t0 = ((int*)(src0 + i))[0];
				int t1 = ((int*)(src1 + i))[0];

				((int*)(dst0 + i))[0] = t1;
				((int*)(dst1 + i))[0] = t0;
			}
		}

		for (; i < size.width; i++) {
			uchar t0 = src0[i];
			uchar t1 = src1[i];

			dst0[i] = t1;
			dst1[i] = t0;
		}
	}

	return 0;
}

} // namespace fbc

#endif // FBC_CV_FLIP_HPP_

测试代码test_flip.cpp:

#include "test_flip.hpp"
#include <assert.h>
#include <iostream>
#include <string>

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

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

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

	int flipCode[3] {-1, 0, 1}; // both axes, x axis, y axis

	for (int i = 0; i < 3; i++) {
		fbc::Mat_<uchar, 3> mat1(height, width, matSrc.data);
		fbc::Mat_<uchar, 3> mat2(height, width);
		fbc::flip(mat1, mat2, flipCode[i]);

		cv::Mat mat1_(height, width, CV_8UC3, matSrc.data);
		cv::Mat mat2_;
		cv::flip(mat1_, mat2_, flipCode[i]);

		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]);
			}
		}

		std::string name = std::to_string(i);
		std::string file_path = "E:/GitCode/OpenCV_Test/test_images/";
		std::string name_fbc = file_path + "flip_fbc_" + name + ".jpg";
		std::string name_cv = file_path + "flip_cv_" + name + ".jpg";
		cv::Mat matSave(height, width, CV_8UC3, mat2.data);
		cv::imwrite(name_fbc, matSave);
		cv::imwrite(name_cv, mat2_);
	}

	return 0;
}

int test_flip_float()
{
	cv::Mat matSrc = cv::imread("E:/GitCode/OpenCV_Test/test_images/1.jpg", 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;

	int flipCode[3] {-1, 0, 1}; // both axes, x axis, y axis

	for (int i = 0; i < 3; i++) {
		fbc::Mat_<float, 1> mat1(height, width, matSrc.data);
		fbc::Mat_<float, 1> mat2(height, width);
		fbc::flip(mat1, mat2, flipCode[i]);

		cv::Mat mat1_(height, width, CV_32FC1, matSrc.data);
		cv::Mat mat2_;
		cv::flip(mat1_, mat2_, flipCode[i]);

		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

OpenCV代码提取:flip函数的实现的更多相关文章

  1. OpenCV代码提取:transpose函数的实现

    OpenCV中的transpose函数实现图像转置,公式为: 目前fbc_cv库中也实现了transpose函数,支持多通道,uchar和float两种数据类型,经测试,与OpenCV3.1结果完全一 ...

  2. OpenCV代码提取:dft函数的实现

    The Fourier Transform will decompose an image into its sinus and cosines components. In other words, ...

  3. OpenCV代码提取: threshold函数的实现

    threshold algorithm: The simplest image segmentation method. All thresholding algorithms take a sour ...

  4. OpenCV代码提取:遍历指定目录下指定文件的实现

    前言 OpenCV 3.1之前的版本,在contrib目录下有提供遍历文件的函数,用起来比较方便.但是在最新的OpenCV 3.1版本给去除掉了.为了以后使用方便,这里将OpenCV 2.4.9中相关 ...

  5. opencv: flip函数的使用;

    flip函数用于图像翻转,比较方便.在opencv中有几种形式: C++: void flip(InputArray src, OutputArray dst, int flipCode) Pytho ...

  6. OpenCV中的绘图函数-OpenCV步步精深

    OpenCV 中的绘图函数 画线 首先要为画的线创造出环境,就要生成一个空的黑底图像 img=np.zeros((512,512,3), np.uint8) 这是黑色的底,我们的画布,我把窗口名叫做i ...

  7. 基础学习笔记之opencv(24):imwrite函数的使用

    http://www.cnblogs.com/tornadomeet/archive/2012/12/26/2834336.html 前言 OpenCV中保存图片的函数在c++版本中变成了imwrit ...

  8. (转)Uri详解之——Uri结构与代码提取

    前言:依然没有前言…… 相关博客:1.<Uri详解之——Uri结构与代码提取>2.<Uri详解之二——通过自定义Uri外部启动APP与Notification启动> 上几篇给大 ...

  9. Uri详解之——Uri结构与代码提取

    目录(?)[+] 前言:依然没有前言…… 相关博客:1.<Uri详解之——Uri结构与代码提取>2.<Uri详解之二——通过自定义Uri外部启动APP与Notification启动& ...

随机推荐

  1. note02-计算机网络

    2.物理层 通信系统模型(源->发送器->XXX->接收器->终),源发出数字信号,调制器编码为模拟信号,进行传输,解调器解码模拟信号为数字信号给终 信噪比,香农公式,C=B  ...

  2. 编程思想的理解(POP,OOP,SOA,AOP)

    http://blog.csdn.net/hawksoft/article/details/7021435 1)POP--面向过程编程(Process-oriented programming ):面 ...

  3. POJ 最小球覆盖 模拟退火

    最小球覆盖:用半径最小的球去覆盖所有点. 纯粹的退火算法,是搞不定的,精度不够,不然就会TLE,根本跑不出答案来. 任取一点为球心,然后一点点靠近最远点.其实这才是最主要的. 因为:4个点确定一个球, ...

  4. Codeforces Round #432 (Div. 2)

    A. Arpa and a research in Mexican wave Arpa is researching the Mexican wave. There are n spectators ...

  5. 【转】不错的linux下通用的java程序启动脚本

    虽然写起动shell的频率非常不高...但是每次要写都要对付一大堆的jar文件路径,新加jar包也必须要修改起动shell. 在网上找到一个挺好的通用shell脚本. 只需要修改一些配置变量,就可以用 ...

  6. 【luogu P3808 AC自动机(简单版)】 模板

    题目链接:https://www.luogu.org/problemnew/show/P3808 #include <queue> #include <cstdio> #inc ...

  7. Android学习笔记_19_广播接收者 BroadcastReceiver及其应用_窃听短信_拦截外拨电话

    一.广播接收者类型: 广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”. 普通广播是完全异步的,可以在同一时刻(逻辑上 ...

  8. kinect v2

    http://www.tuicool.com/articles/NbmyyeU https://channel9.msdn.com/Blogs/raw-tech/Making-your-body-th ...

  9. o'Reill的SVG精髓(第二版)学习笔记——第十二章

    第十二章 SVG动画 12.1动画基础 SVG的动画特性基于万维网联盟的“同步多媒体集成语言”(SMIL)规范(http://www.w3.org/TR/SMIL3). 在这个动画系统中,我们可以指定 ...

  10. o'Reill的SVG精髓(第二版)学习笔记——第五章

    第五章 文档结构 5.1 结构与表现 XML的目标之一便是提供一种能将结构从视觉表示中独立出来的方法. 但是不幸的是,关于XML的很多讨论都强调结构而非表现. 我们将通过详细讨论如何在SVG中指定表现 ...