Commit a4a8b84e authored by Tham's avatar Tham Committed by Maksim Shabunin

Implement image hash modules (#688)

* first commit

* first commit

* adjust code layout

* round mean value

* add missed header

* remove useless header

* remove useless header

* first commit

* first commit

* first commit

* Encapsule function averageHash by class

* remove export macro

* encapsulate phash algo by class

* first commit

* fix bugs of createHash and fillBlcoks

* 1 : add create function
2 : add overload functions

* implement get set functions

* fix bug--destination depth should be CV_32F

* first commit

* first commit

* 1 : fix bug--forgot '"'
2 : forgot to include iostream

* fix warnings

* remove tab

* remove trailing white space

* remove trailing white space

* remove trailing white space

* remove trailing white space

* remove trailing white space

* remove trailing white space

* first commit

* remove trailing white space

* remove trailing white space

* remove trailing white space

* reduce redundance operation

* add explanation of img_hash

* remove useless comments

* remove trailing space

* first commit

* fix missed symbol

* add new defgroup and change all defgroup to ihash

* fix namespace confliction

* change namespace from ihash to img_hash

* change ihash to img_hash

* change include guard

* forbid implicit conversion

* first commit

* 1 : declare function findFeatureVector
2 : forward declare test class--RavialVarHashTester as friend

* first commit

* replace auto with explicit type

* export some symbols, for initialization and testing

* remove trailing white space

* add namespace cv

* fix type cast warning and define default constrcutor/destructor

* declare and define RadialVarHashTester in namespace

* remove default constructor/destructor

* exports functions findFeatures and destructor

* remove trailing white space

* fix bug--wrong definition of destructor

* remove trailing white space

* implement findFeatureVector

* add test case for findFeatureVector

* 1 : fix bug--forgot to allocate space for input
2 : fix bug--compare the results of pixPerLine with wrong matrix

* remove trailing space

* implement hashCalculate

* add test case for hashCalculate

* remove trailing white space

* avoid hiding parameter

* refine codes and keep the original range

* adjust expected hash value since the range of hash change

* add comment

* reduce scope

* remove trailing white space

* adjust format

* add new function compare

* implement compute functions

* use array as buffer of cv::Mat, avoid memory allocation

* remove trailing whitespace

* 1 : implement cross-correlation rather than using matchTemplate since the
results of matchTemplate are weird
2 : remove gamma param, although the paper said PHash apply gamma
correction on the image, but the codes do not do that(I think it is a bug
of PHash)
3 : create function can specify sigma and numOfAngleLine
4 : Use blurImg to replace normalizeImg
5 : remove useless parameters which related to gamma correction

* add example of radial variance hash

* use buffer to avoid memory allocation and use enum to specify hash size

* remove useless header

* fix bug--constructor only accept two params

* add comments

* transpose projection matrix, friendlier for cache hit

* use pointer to access projection value

* function able to specify sigma and numOfAngleLine

* add get/set functions

* implement image hash algo--block mean hash

* include block mean hash and add comments

* remove trailing whitespace

* fix warning--compare with sign and unsigned value

* implement destructor and change mode type to size_t

* add example of block mean hash

* compress the bits of hash

* function--blockMeanHash able to set mode

* fix type cast warning and style

* change expected result to bool

* compress the hash value from 16 bytes to 8 bytes

* update comments

* compress hash from 16 bytes to 8 bytes

* use peak value of cross correlation as comparison result

* add limit header

* first commit

* add group and header file of color moment hash

* should not use auto, it is c++11 feature

* support python binding

* implement destructor of AverageHash

* support python binding

* support python binding

* support python binding

* change type to inputArray and outputArray, easier for python binding

* all algorithms support input type CV_8UC4,CV_8UC3 and CV_8UC1

* Provide better instructions

* Make it more pleasant to read

* Add information of speed comparsion

* remove trailing white space

* remove useless blank line

* refine comments of example

* fix link error

* refine title

* 1 : implement function "getDefaultName"
2 : adjust style

* Update README.md

1 : Fix wrong branch
2 : Add another solution to download img_hash

* img_hash: refactored interfaces to use pImpl

* remove trailing white space

* img_hash: use type-safe pImpl

* change name, easier to find the source file

* 1 : narrow scope of ImgHashImpl
2 : use static cast to replace dynamic cast because class hierarchy of
img_hash is very straightforward

* should not declare ImgHashImpl api in the header file of ImgHashBase, this increase chance of breaking ABI

* should not declare ImgHashImpl api in the header file of ImgHashBase, this increase chance of breaking ABI

* fix warning, because unelaborated friend declaration is a C++11 extension

* first commit

* fix bug, except of windows, other platforms cannot access private member.
pimpl only accessable by the class itself, therefore I think declare
everything as public is quite safe

* first commit comparison and computation charts

* update chart link
parent 8ef2f717
set(the_description "Image hash algorithms")
set(OPENCV_MODULE_IS_PART_OF_WORLD OFF)
ocv_define_module(img_hash opencv_imgproc opencv_core WRAP java python)
Image Hashing algorithms
========================
This module is intended to port the algorithms from PHash library and implement other image hash
algorithm do not exist in PHash library yet.
@misc{lookslikeit,
author={Krawetz, Neal},
title={Looks Like It},
url={http://www.hackerfactor.com/blog/?/archives/432-Looks-Like-It.html}
}
@article{tang2012perceptual,
title={Perceptual hashing for color images using invariant moments},
author={Tang, Zhenjun and Dai, Yumin and Zhang, Xianquan},
journal={Appl. Math},
volume={6},
number={2S},
pages={643S--650S},
year={2012},
url={http://www.phash.org/docs/pubs/thesis_zauner.pdf}
}
@article{zauner2010implementation,
title={Implementation and benchmarking of perceptual image hash functions},
author={Zauner, Christoph},
year={2010},
publisher={na}
}
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_IMG_HASH_H
#define OPENCV_IMG_HASH_H
#include "opencv2/img_hash/average_hash.hpp"
#include "opencv2/img_hash/block_mean_hash.hpp"
#include "opencv2/img_hash/color_moment_hash.hpp"
#include "opencv2/img_hash/marr_hildreth_hash.hpp"
#include "opencv2/img_hash/phash.hpp"
#include "opencv2/img_hash/radial_variance_hash.hpp"
/**
@defgroup img_hash The module brings implementations of different image hashing algorithms.
Provide algorithms to extract the hash of images and fast way to figure out most similar images in
huge data set.
Namespace for all functions is cv::img_hash.
### Supported Algorithms
- Average hash (also called Different hash)
- PHash (also called Perceptual hash)
- Marr Hildreth Hash
- Radial Variance Hash
- Block Mean Hash (modes 0 and 1)
- Color Moment Hash (this is the one and only hash algorithm resist to rotation attack(-90~90 degree))
You can study more about image hashing from following paper and websites:
- "Implementation and benchmarking of perceptual image hash functions" @cite zauner2010implementation
- "Looks Like It" @cite lookslikeit
### Code Example
@include samples/hash_samples.cpp
### Performance under different attacks
![Performance chart](img_hash/doc/attack_performance.JPG)
### Speed comparison with PHash library (100 images from ukbench)
![Hash Computation chart](img_hash/doc/hash_computation_chart.JPG)
![Hash comparison chart](img_hash/doc/hash_comparison_chart.JPG)
As you can see, hash computation speed of img_hash module outperform [PHash library](http://www.phash.org/) a lot.
PS : I do not list out the comparison of Average hash, PHash and Color Moment hash, because I cannot
find them in PHash.
### Motivation
Collects useful image hash algorithms into opencv, so we do not need to rewrite them by ourselves
again and again or rely on another 3rd party library(ex : PHash library). BOVW or correlation
matching are good and robust, but they are very slow compare with image hash, if you need to deal
with large scale CBIR(content based image retrieval) problem, image hash is a more reasonable
solution.
### More info
You can learn more about img_hash modules from following links, these links show you how to find
similar image from ukbench dataset, provide thorough benchmark of different attacks(contrast, blur,
noise(gaussion,pepper and salt), jpeg compression, watermark, resize).
* [Introduction to image hash module of opencv](http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html)
* [Speed up image hashing of opencv(img_hash) and introduce color moment hash](http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of-opencvimghash.html)
### Contributors
Tham Ngap Wei, thamngapwei@gmail.com
*/
#endif // OPENCV_IMG_HASH_H
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_AVERAGE_HASH_HPP
#define OPENCV_AVERAGE_HASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief Computes average hash value of the input image
This is a fast image hashing algorithm, but only work on simple case. For more details, please
refer to @cite lookslikeit
*/
class CV_EXPORTS_W AverageHash : public ImgHashBase
{
public:
CV_WRAP static Ptr<AverageHash> create();
protected:
AverageHash() {}
};
/** @brief Calculates img_hash::AverageHash in one call
@param inputArr input image want to compute hash value, type should be CV_8UC4, CV_8UC3 or CV_8UC1.
@param outputArr Hash value of input, it will contain 16 hex decimal number, return type is CV_8U
*/
CV_EXPORTS_W void averageHash(cv::InputArray inputArr, cv::OutputArray outputArr);
//! @}
}} // cv::img_hash::
#endif // OPENCV_AVERAGE_HASH_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_BLOCK_MEAN_HASH_HPP
#define OPENCV_BLOCK_MEAN_HASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
enum BlockMeanHashMode
{
BLOCK_MEAN_HASH_MODE_0 = 0, //!< use fewer block and generate 16*16/8 uchar hash value
BLOCK_MEAN_HASH_MODE_1 = 1, //!< use block blocks(step sizes/2), generate 31*31/8 + 1 uchar hash value
};
/** @brief Image hash based on block mean.
See @cite zauner2010implementation for details.
*/
class CV_EXPORTS_W BlockMeanHash : public ImgHashBase
{
public:
/** @brief Create BlockMeanHash object
@param mode
*/
CV_WRAP void setMode(int mode);
CV_WRAP std::vector<double> getMean() const;
CV_WRAP static Ptr<BlockMeanHash> create(int mode = BLOCK_MEAN_HASH_MODE_0);
protected:
BlockMeanHash() {}
};
/** @brief Computes block mean hash of the input image
@param inputArr input image want to compute hash value, type should be CV_8UC4, CV_8UC3 or CV_8UC1.
@param outputArr Hash value of input, it will contain 16 hex decimal number, return type is CV_8U
@param mode
*/
CV_EXPORTS_W void blockMeanHash(cv::InputArray inputArr,
cv::OutputArray outputArr,
int mode = BLOCK_MEAN_HASH_MODE_0);
//! @}
}} // cv::img_hash::
#endif // OPENCV_BLOCK_MEAN_HASH_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_COLOR_MOMENT_HASH_HPP
#define OPENCV_COLOR_MOMENT_HASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief Image hash based on color moments.
See @cite tang2012perceptual for details.
*/
class CV_EXPORTS_W ColorMomentHash : public ImgHashBase
{
public:
CV_WRAP static Ptr<ColorMomentHash> create();
protected:
ColorMomentHash() {}
};
/** @brief Computes color moment hash of the input, the algorithm
is come from the paper "Perceptual Hashing for Color Images
Using Invariant Moments"
@param inputArr input image want to compute hash value,
type should be CV_8UC4, CV_8UC3 or CV_8UC1.
@param outputArr 42 hash values with type CV_64F(double)
*/
CV_EXPORTS_W void colorMomentHash(cv::InputArray inputArr, cv::OutputArray outputArr);
//! @}
}} // cv::img_hash::
#endif // OPENCV_COLOR_MOMENT_HASH_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_IMG_HASH_BASE_HPP
#define OPENCV_IMG_HASH_BASE_HPP
#include "opencv2/core.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief The base class for image hash algorithms
*/
class CV_EXPORTS_W ImgHashBase : public Algorithm
{
public:
class ImgHashImpl;
~ImgHashBase();
/** @brief Computes hash of the input image
@param inputArr input image want to compute hash value
@param outputArr hash of the image
*/
CV_WRAP void compute(cv::InputArray inputArr, cv::OutputArray outputArr);
/** @brief Compare the hash value between inOne and inTwo
@param hashOne Hash value one
@param hashTwo Hash value two
@return value indicate similarity between inOne and inTwo, the meaning
of the value vary from algorithms to algorithms
*/
CV_WRAP double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const;
protected:
ImgHashBase();
protected:
Ptr<ImgHashImpl> pImpl;
};
//! @}
} } // cv::img_hash::
#endif // OPENCV_IMG_HASH_BASE_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_MARR_HILDRETH_HASH_HPP
#define OPENCV_MARR_HILDRETH_HASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief Marr-Hildreth Operator Based Hash, slowest but more discriminative.
See @cite zauner2010implementation for details.
*/
class CV_EXPORTS_W MarrHildrethHash : public ImgHashBase
{
public:
/**
* @brief self explain
*/
CV_WRAP float getAlpha() const;
/**
* @brief self explain
*/
CV_WRAP float getScale() const;
/** @brief Set Mh kernel parameters
@param alpha int scale factor for marr wavelet (default=2).
@param scale int level of scale factor (default = 1)
*/
CV_WRAP void setKernelParam(float alpha, float scale);
/**
@param alpha int scale factor for marr wavelet (default=2).
@param scale int level of scale factor (default = 1)
*/
CV_WRAP static Ptr<MarrHildrethHash> create(float alpha = 2.0f, float scale = 1.0f);
protected:
MarrHildrethHash() {}
};
/** @brief Computes average hash value of the input image
@param inputArr input image want to compute hash value,
type should be CV_8UC4, CV_8UC3, CV_8UC1.
@param outputArr Hash value of input, it will contain 16 hex
decimal number, return type is CV_8U
@param alpha int scale factor for marr wavelet (default=2).
@param scale int level of scale factor (default = 1)
*/
CV_EXPORTS_W void marrHildrethHash(cv::InputArray inputArr,
cv::OutputArray outputArr,
float alpha = 2.0f, float scale = 1.0f);
//! @}
}} // cv::img_hash::
#endif // OPENCV_MARR_HILDRETH_HASH_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_PHASH_HPP
#define OPENCV_PHASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief pHash
Slower than average_hash, but tolerant of minor modifications
This algorithm can combat more variation than averageHash, for more details please refer to @cite lookslikeit
*/
class CV_EXPORTS_W PHash : public ImgHashBase
{
public:
CV_WRAP static Ptr<PHash> create();
protected:
PHash() {}
};
/** @brief Computes pHash value of the input image
@param inputArr input image want to compute hash value,
type should be CV_8UC4, CV_8UC3, CV_8UC1.
@param outputArr Hash value of input, it will contain 8 uchar value
*/
CV_EXPORTS_W void pHash(cv::InputArray inputArr, cv::OutputArray outputArr);
//! @}
} } // cv::img_hash::
#endif // OPENCV_PHASH_HPP
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_RADIAL_VARIANCE_HASH_HPP
#define OPENCV_RADIAL_VARIANCE_HASH_HPP
#include "img_hash_base.hpp"
namespace cv {
namespace img_hash {
//! @addtogroup img_hash
//! @{
/** @brief Image hash based on Radon transform.
See @cite tang2012perceptual for details.
*/
class CV_EXPORTS_W RadialVarianceHash : public ImgHashBase
{
public:
CV_WRAP static Ptr<RadialVarianceHash> create(double sigma = 1, int numOfAngleLine = 180);
CV_WRAP int getNumOfAngleLine() const;
CV_WRAP double getSigma() const;
CV_WRAP void setNumOfAngleLine(int value);
CV_WRAP void setSigma(double value);
// internals
std::vector<double> getFeatures();
cv::Mat getHash();
Mat getPixPerLine(Mat const &input);
Mat getProjection();
protected:
RadialVarianceHash() {}
};
/** @brief Computes radial variance hash of the input image
@param inputArr input image want to compute hash value,
type should be CV_8UC4, CV_8UC3, CV_8UC1.
@param outputArr Hash value of input
@param sigma Gaussian kernel standard deviation
@param numOfAngleLine The number of angles to consider
*/
CV_EXPORTS_W void radialVarianceHash(cv::InputArray inputArr,
cv::OutputArray outputArr,
double sigma = 1,
int numOfAngleLine = 180);
//! @}
}} // cv::img_hash::
#endif // OPENCV_RADIAL_VARIANCE_HASH_HPP
#include "opencv2/core.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/img_hash.hpp"
#include <iostream>
using namespace cv;
using namespace cv::img_hash;
using namespace std;
template <typename T>
inline void test_one(const std::string &title, const Mat &a, const Mat &b)
{
cout << "=== " << title << " ===" << endl;
TickMeter tick;
Mat hashA, hashB;
Ptr<ImgHashBase> func;
func = T::create();
tick.reset(); tick.start();
func->compute(a, hashA);
tick.stop();
cout << "compute1: " << tick.getTimeMilli() << " ms" << endl;
tick.reset(); tick.start();
func->compute(b, hashB);
tick.stop();
cout << "compute2: " << tick.getTimeMilli() << " ms" << endl;
cout << "compare: " << func->compare(hashA, hashB) << endl << endl;;
}
int main(int argc, char **argv)
{
if (argc != 3)
{
cerr << "must input the path of input image and target image. ex : hash_samples lena.jpg lena2.jpg" << endl;
return -1;
}
ocl::setUseOpenCL(false);
Mat input = imread(argv[1]);
Mat target = imread(argv[2]);
test_one<AverageHash>("AverageHash", input, target);
test_one<PHash>("PHash", input, target);
test_one<MarrHildrethHash>("MarrHildrethHash", input, target);
test_one<RadialVarianceHash>("RadialVarianceHash", input, target);
test_one<BlockMeanHash>("BlockMeanHash", input, target);
return 0;
}
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace std;
using namespace img_hash;
namespace {
class AverageHashImpl : public ImgHashBase::ImgHashImpl
{
private:
cv::Mat bitsImg;
cv::Mat grayImg;
cv::Mat resizeImg;
public:
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
cv::Mat const input = inputArr.getMat();
CV_Assert(input.type() == CV_8UC4 ||
input.type() == CV_8UC3 ||
input.type() == CV_8U);
cv::resize(input, resizeImg, cv::Size(8,8));
if(input.type() == CV_8UC3)
{
cv::cvtColor(resizeImg, grayImg, CV_BGR2GRAY);
}
else if(input.type() == CV_8UC4)
{
cv::cvtColor(resizeImg, grayImg, CV_BGRA2GRAY);
}
else
{
grayImg = resizeImg;
}
uchar const imgMean = static_cast<uchar>(cvRound(cv::mean(grayImg)[0]));
cv::compare(grayImg, imgMean, bitsImg, CMP_GT);
bitsImg /= 255;
outputArr.create(1, 8, CV_8U);
cv::Mat hash = outputArr.getMat();
uchar *hash_ptr = hash.ptr<uchar>(0);
uchar const *bits_ptr = bitsImg.ptr<uchar>(0);
std::bitset<8> bits;
for(size_t i = 0, j = 0; i != bitsImg.total(); ++j)
{
for(size_t k = 0; k != 8; ++k)
{
//avoid warning C4800, casting do not work
bits[k] = bits_ptr[i++] != 0;
}
hash_ptr[j] = static_cast<uchar>(bits.to_ulong());
}
}
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return norm(hashOne, hashTwo, NORM_HAMMING);
}
};
} // namespace::
//==================================================================================================
namespace cv { namespace img_hash {
Ptr<AverageHash> AverageHash::create()
{
Ptr<AverageHash> res(new AverageHash());
res->pImpl = makePtr<AverageHashImpl>();
return res;
}
void averageHash(cv::InputArray inputArr, cv::OutputArray outputArr)
{
AverageHashImpl().compute(inputArr, outputArr);
}
}} // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::img_hash;
using namespace std;
namespace {
enum
{
imgWidth = 256,
imgHeight = 256,
blockWidth = 16,
blockHeigth = 16,
blockPerCol = imgHeight / blockHeigth,
blockPerRow = imgWidth / blockWidth,
rowSize = imgHeight - blockHeigth,
colSize = imgWidth - blockWidth
};
class BlockMeanHashImpl : public ImgHashBase::ImgHashImpl
{
public:
BlockMeanHashImpl(int mode)
{
setMode(mode);
}
~BlockMeanHashImpl() {}
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
cv::Mat const input = inputArr.getMat();
CV_Assert(input.type() == CV_8UC4 ||
input.type() == CV_8UC3 ||
input.type() == CV_8U);
cv::resize(input, resizeImg_, cv::Size(imgWidth,imgHeight));
if(input.type() == CV_8UC3)
{
cv::cvtColor(resizeImg_, grayImg_, CV_BGR2GRAY);
}
else if(input.type() == CV_8UC4)
{
cv::cvtColor(resizeImg_, grayImg_, CV_BGRA2GRAY);
}
else
{
grayImg_ = resizeImg_;
}
int pixColStep = blockWidth;
int pixRowStep = blockHeigth;
int numOfBlocks = 0;
switch(mode_)
{
case BLOCK_MEAN_HASH_MODE_0:
{
numOfBlocks = blockPerCol * blockPerRow;
break;
}
case BLOCK_MEAN_HASH_MODE_1:
{
pixColStep /= 2;
pixRowStep /= 2;
numOfBlocks = (blockPerCol*2-1) * (blockPerRow*2-1);
break;
}
default:
break;
}
mean_.resize(numOfBlocks);
findMean(pixRowStep, pixColStep);
outputArr.create(1, numOfBlocks/8 + numOfBlocks % 8, CV_8U);
cv::Mat hash = outputArr.getMat();
createHash(hash);
}
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return norm(hashOne, hashTwo, NORM_HAMMING);
}
void setMode(int mode)
{
CV_Assert(mode == BLOCK_MEAN_HASH_MODE_0 || mode == BLOCK_MEAN_HASH_MODE_1);
mode_ = mode;
}
void createHash(cv::Mat &hash)
{
double const median = cv::mean(grayImg_)[0];
uchar *hashPtr = hash.ptr<uchar>(0);
std::bitset<8> bits = 0;
for(size_t i = 0; i < mean_.size(); ++i)
{
size_t const residual = i%8;
bits[residual] = mean_[i] < median ? 0 : 1;
if(residual == 7)
{
*hashPtr = static_cast<uchar>(bits.to_ulong());
++hashPtr;
}else if(i == mean_.size() - 1)
{
*hashPtr = bits[residual];
}
}
}
void findMean(int pixRowStep, int pixColStep)
{
size_t blockIdx = 0;
for(int row = 0; row <= rowSize; row += pixRowStep)
{
for(int col = 0; col <= colSize; col += pixColStep)
{
mean_[blockIdx++] = cv::mean(grayImg_(cv::Rect(col, row, blockWidth, blockHeigth)))[0];
}
}
}
cv::Mat grayImg_;
std::vector<double> mean_;
int mode_;
cv::Mat resizeImg_;
};
inline BlockMeanHashImpl *getLocalImpl(ImgHashBase::ImgHashImpl *ptr)
{
BlockMeanHashImpl * impl = static_cast<BlockMeanHashImpl*>(ptr);
CV_Assert(impl);
return impl;
}
}
//==================================================================================================
namespace cv { namespace img_hash {
Ptr<BlockMeanHash> BlockMeanHash::create(int mode)
{
Ptr<BlockMeanHash> res(new BlockMeanHash);
res->pImpl = makePtr<BlockMeanHashImpl>(mode);
return res;
}
void BlockMeanHash::setMode(int mode)
{
getLocalImpl(pImpl)->setMode(mode);
}
std::vector<double> BlockMeanHash::getMean() const
{
return getLocalImpl(pImpl)->mean_;
}
void blockMeanHash(cv::InputArray inputArr, cv::OutputArray outputArr, int mode)
{
BlockMeanHashImpl(mode).compute(inputArr, outputArr);
}
}} // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::img_hash;
using namespace std;
namespace {
class ColorMomentHashImpl : public ImgHashBase::ImgHashImpl
{
public:
~ColorMomentHashImpl() {}
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
cv::Mat const input = inputArr.getMat();
CV_Assert(input.type() == CV_8UC4 ||
input.type() == CV_8UC3 ||
input.type() == CV_8U);
if(input.type() == CV_8UC3)
{
colorImg_ = input;
}
else if(input.type() == CV_8UC4)
{
cv::cvtColor(input, colorImg_, CV_BGRA2BGR);
}
else
{
cv::cvtColor(input, colorImg_, CV_GRAY2BGR);
}
cv::resize(colorImg_, resizeImg_, cv::Size(512,512), 0, 0,
INTER_CUBIC);
cv::GaussianBlur(resizeImg_, blurImg_, cv::Size(3,3), 0, 0);
cv::cvtColor(blurImg_, colorSpace_, CV_BGR2HSV);
cv::split(colorSpace_, channels_);
outputArr.create(1, 42, CV_64F);
cv::Mat hash = outputArr.getMat();
hash.setTo(0);
computeMoments(hash.ptr<double>(0));
cv::cvtColor(blurImg_, colorSpace_, CV_BGR2YCrCb);
cv::split(colorSpace_, channels_);
computeMoments(hash.ptr<double>(0) + 21);
}
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return norm(hashOne, hashTwo, NORM_L2) * 10000;
}
private:
void computeMoments(double *inout)
{
for(size_t i = 0; i != channels_.size(); ++i)
{
cv::HuMoments(cv::moments(channels_[i]), inout);
inout += 7;
}
}
private:
cv::Mat blurImg_;
cv::Mat colorImg_;
std::vector<cv::Mat> channels_;
cv::Mat colorSpace_;
cv::Mat resizeImg_;
};
}
//==================================================================================================
namespace cv { namespace img_hash {
Ptr<ColorMomentHash> ColorMomentHash::create()
{
Ptr<ColorMomentHash> res(new ColorMomentHash);
res->pImpl = makePtr<ColorMomentHashImpl>();
return res;
}
void colorMomentHash(cv::InputArray inputArr, cv::OutputArray outputArr)
{
ColorMomentHashImpl().compute(inputArr, outputArr);
}
} } // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
namespace cv {
namespace img_hash{
ImgHashBase::ImgHashBase()
{
}
ImgHashBase::~ImgHashBase()
{
}
void ImgHashBase::compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
pImpl->compute(inputArr, outputArr);
}
double ImgHashBase::compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return pImpl->compare(hashOne, hashTwo);
}
} } // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::img_hash;
using namespace std;
namespace {
void getMHKernel(float alpha, float level, cv::Mat &kernel)
{
int const sigma = static_cast<int>(4*std::pow(alpha,level));
float const ratio = std::pow(alpha, -level);
kernel.create(2*sigma+1, 2*sigma+1, CV_32F);
for(int row = 0; row != kernel.rows; ++row)
{
float const ydiff = static_cast<float>(row - sigma);
float const ypos = ratio * ydiff;
float const yposPow2 = ypos * ypos;
float *kPtr = kernel.ptr<float>(row);
for(int col = 0; col != kernel.cols; ++col)
{
float const xpos = ratio * static_cast<float>((col - sigma));
float const a = xpos * xpos + yposPow2;
kPtr[col] = (2-a)*std::exp(a/2);
}
}
}
void fillBlocks(cv::Mat const &freImg, cv::Mat &blocks)
{
//TODO : use forEach may provide better speed, however,
//it is quite tedious to apply without lambda
blocks.setTo(0);
for(int row = 0; row != blocks.rows; ++row)
{
float *bptr = blocks.ptr<float>(row);
int const rOffset = row*16;
for(int col = 0; col != blocks.cols; ++col)
{
cv::Rect const roi(rOffset,col*16,16,16);
bptr[col] =
static_cast<float>(cv::sum(freImg(roi))[0]);
}
}
}
void createHash(cv::Mat const &blocks, cv::Mat &hash)
{
int hash_index = 0;
int bit_index = 0;
uchar hashbyte = 0;
uchar *hashPtr = hash.ptr<uchar>(0);
for (int row=0; row < 29; row += 4)
{
for (int col=0; col < 29; col += 4)
{
cv::Rect const roi(col,row,3,3);
cv::Mat const blockROI = blocks(roi);
float const avg =
static_cast<float>(cv::sum(blockROI)[0]/9.0);
for(int i = 0; i != blockROI.rows; ++i)
{
float const *bptr = blockROI.ptr<float>(i);
for(int j = 0; j != blockROI.cols; ++j)
{
hashbyte <<= 1;
if (bptr[j] > avg)
{
hashbyte |= 0x01;
}
++bit_index;
if ((bit_index%8) == 0)
{
hash_index = (bit_index/8) - 1;
hashPtr[hash_index] = hashbyte;
hashbyte = 0x00;
}
}
}
}
}
}
class MarrHildrethHashImpl : public ImgHashBase::ImgHashImpl
{
public:
MarrHildrethHashImpl(float alpha = 2.0f, float scale = 1.0f) : alphaVal(alpha), scaleVal(scale)
{
getMHKernel(alphaVal, scaleVal, mhKernel);
blocks.create(31,31, CV_32F);
}
~MarrHildrethHashImpl() { }
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
cv::Mat const input = inputArr.getMat();
CV_Assert(input.type() == CV_8UC4 ||
input.type() == CV_8UC3 ||
input.type() == CV_8U);
if(input.type() == CV_8UC3)
{
cv::cvtColor(input, grayImg, CV_BGR2GRAY);
}
else if(input.type() == CV_8UC4)
{
cv::cvtColor(input, grayImg, CV_BGRA2GRAY);
}
else
{
grayImg = input;
}
//pHash use Canny-deritch filter to blur the image
cv::GaussianBlur(grayImg, blurImg, cv::Size(7, 7), 0);
cv::resize(blurImg, resizeImg, cv::Size(512, 512), 0, 0, INTER_CUBIC);
cv::equalizeHist(resizeImg, equalizeImg);
//extract frequency info by mh kernel
cv::filter2D(equalizeImg, freImg, CV_32F, mhKernel);
fillBlocks(freImg, blocks);
outputArr.create(1, 72, CV_8U);
cv::Mat hash = outputArr.getMat();
createHash(blocks, hash);
}
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return norm(hashOne, hashTwo, NORM_HAMMING);
}
float getAlpha() const
{
return alphaVal;
}
float getScale() const
{
return scaleVal;
}
void setKernelParam(float alpha, float scale)
{
alphaVal = alpha;
scaleVal = scale;
getMHKernel(alphaVal, scaleVal, mhKernel);
}
friend class MarrHildrethHash;
private:
float alphaVal;
cv::Mat blocks;
cv::Mat blurImg;
cv::Mat equalizeImg;
cv::Mat freImg; //frequency response image
cv::Mat grayImg;
cv::Mat mhKernel;
cv::Mat resizeImg;
float scaleVal;
};
inline MarrHildrethHashImpl *getLocalImpl(ImgHashBase::ImgHashImpl *ptr)
{
MarrHildrethHashImpl * impl = static_cast<MarrHildrethHashImpl*>(ptr);
CV_Assert(impl);
return impl;
}
}
//==================================================================================================
namespace cv { namespace img_hash {
float MarrHildrethHash::getAlpha() const
{
return getLocalImpl(pImpl)->getAlpha();
}
float MarrHildrethHash::getScale() const
{
return getLocalImpl(pImpl)->getScale();
}
void MarrHildrethHash::setKernelParam(float alpha, float scale)
{
getLocalImpl(pImpl)->setKernelParam(alpha, scale);
}
Ptr<MarrHildrethHash> MarrHildrethHash::create(float alpha, float scale)
{
Ptr<MarrHildrethHash> res(new MarrHildrethHash);
res->pImpl = makePtr<MarrHildrethHashImpl>(alpha, scale);
return res;
}
void marrHildrethHash(cv::InputArray inputArr,
cv::OutputArray outputArr,
float alpha, float scale)
{
MarrHildrethHashImpl(alpha, scale).compute(inputArr, outputArr);
}
} } // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::img_hash;
using namespace std;
namespace {
class PHashImpl : public ImgHashBase::ImgHashImpl
{
public:
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr)
{
cv::Mat const input = inputArr.getMat();
CV_Assert(input.type() == CV_8UC4 ||
input.type() == CV_8UC3 ||
input.type() == CV_8U);
cv::resize(input, resizeImg, cv::Size(32,32));
if(input.type() == CV_8UC3)
{
cv::cvtColor(resizeImg, grayImg, CV_BGR2GRAY);
}
else if(input.type() == CV_8UC4)
{
cv::cvtColor(resizeImg, grayImg, CV_BGRA2GRAY);
}
else
{
grayImg = resizeImg;
}
grayImg.convertTo(grayFImg, CV_32F);
cv::dct(grayFImg, dctImg);
dctImg(cv::Rect(0, 0, 8, 8)).copyTo(topLeftDCT);
topLeftDCT.at<float>(0, 0) = 0;
float const imgMean = static_cast<float>(cv::mean(topLeftDCT)[0]);
cv::compare(topLeftDCT, imgMean, bitsImg, CMP_GT);
bitsImg /= 255;
outputArr.create(1, 8, CV_8U);
cv::Mat hash = outputArr.getMat();
uchar *hash_ptr = hash.ptr<uchar>(0);
uchar const *bits_ptr = bitsImg.ptr<uchar>(0);
std::bitset<8> bits;
for(size_t i = 0, j = 0; i != bitsImg.total(); ++j)
{
for(size_t k = 0; k != 8; ++k)
{
//avoid warning C4800, casting do not work
bits[k] = bits_ptr[i++] != 0;
}
hash_ptr[j] = static_cast<uchar>(bits.to_ulong());
}
}
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const
{
return norm(hashOne, hashTwo, NORM_HAMMING);
}
private:
cv::Mat bitsImg;
cv::Mat dctImg;
cv::Mat grayFImg;
cv::Mat grayImg;
cv::Mat resizeImg;
cv::Mat topLeftDCT;
};
} // namespace::
//==================================================================================================
namespace cv { namespace img_hash {
Ptr<PHash> PHash::create()
{
Ptr<PHash> res(new PHash);
res->pImpl = makePtr<PHashImpl>();
return res;
}
void pHash(cv::InputArray inputArr, cv::OutputArray outputArr)
{
PHashImpl().compute(inputArr, outputArr);
}
} } // cv::img_hash::
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_IMG_HASH_PRECOMP_H
#define OPENCV_IMG_HASH_PRECOMP_H
#include "opencv2/core.hpp"
#include "opencv2/core/base.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgproc/types_c.h"
#include "opencv2/img_hash.hpp"
#include <bitset>
#include <iostream>
namespace cv{ namespace img_hash {
class ImgHashBase::ImgHashImpl
{
public:
virtual void compute(cv::InputArray inputArr, cv::OutputArray outputArr) = 0;
virtual double compare(cv::InputArray hashOne, cv::InputArray hashTwo) const = 0;
virtual ~ImgHashImpl() {}
};
}} // cv::img_hash::
#endif // OPENCV_IMG_HASH_PRECOMP_H
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <bitset>
using namespace cv;
class CV_AverageHashTest : public cvtest::BaseTest
{
public:
CV_AverageHashTest();
~CV_AverageHashTest();
protected:
void run(int /* idx */);
};
CV_AverageHashTest::CV_AverageHashTest(){}
CV_AverageHashTest::~CV_AverageHashTest(){}
void CV_AverageHashTest::run(int )
{
cv::Mat const input = (cv::Mat_<uchar>(8, 8) <<
1, 5, 4, 6, 3, 2, 7, 8,
2, 4, 8, 9, 2, 1, 4, 3,
3, 4, 5, 7, 9, 8, 7, 6,
1, 2, 3, 4, 5, 6, 7, 8,
8, 7, 2, 3, 6, 4, 5, 1,
3, 4, 1, 2, 9, 8, 4, 2,
6, 7, 8, 9, 7, 4, 3, 2,
8, 7, 6, 5, 4, 3, 2, 1);
cv::Mat hash;
cv::img_hash::averageHash(input, hash);
bool const expectResult[] =
{
0,0,0,1,0,0,1,1,
0,0,1,1,0,0,0,0,
0,0,0,1,1,1,1,1,
0,0,0,0,0,1,1,1,
1,1,0,0,1,0,0,0,
0,0,0,0,1,1,0,0,
1,1,1,1,1,0,0,0,
1,1,1,0,0,0,0,0
};
uchar const *hashPtr = hash.ptr<uchar>(0);
for(int i = 0; i != hash.cols; ++i)
{
std::bitset<8> const bits = hashPtr[i];
for(int j = 0; j != 8; ++j)
{
EXPECT_EQ(bits[j], expectResult[i*8+j]);
}
}
}
TEST(average_hash_test, accuracy) { CV_AverageHashTest test; test.safe_run(); }
This diff is collapsed.
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
CV_TEST_MAIN("cv")
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
using namespace cv;
class CV_MarrHildrethTest : public cvtest::BaseTest
{
public:
CV_MarrHildrethTest();
~CV_MarrHildrethTest();
protected:
void run(int /* idx */);
};
CV_MarrHildrethTest::CV_MarrHildrethTest(){}
CV_MarrHildrethTest::~CV_MarrHildrethTest(){}
void CV_MarrHildrethTest::run(int )
{
cv::Mat_<uchar> input(512,512);
int val = 0;
for(int row = 0; row != input.rows; ++row)
{
for(int col = 0; col != input.cols; ++col)
{
input.at<uchar>(row, col) = val % 256;
++val;
}
}
cv::Mat hash;
cv::img_hash::marrHildrethHash(input, hash);
uchar const expectResult[] =
{
252, 126, 63, 31, 143, 199, 227, 241,
248, 252, 126, 63, 31, 143, 199, 227,
241, 248, 252, 126, 63, 31, 143, 199,
227, 241, 248, 252, 126, 63, 31, 143,
199, 227, 241, 248, 31, 143, 199, 227,
241, 248, 252, 126, 63, 252, 126, 63,
31, 143, 199, 227, 241, 248, 252, 126,
63, 31, 143, 199, 227, 241, 248, 252,
126, 63, 31, 143, 199, 227, 241, 248
};
uchar const *hashPtr = hash.ptr<uchar>(0);
for(int i = 0; i != 72; ++i)
{
if(hashPtr[i] != expectResult[i])
{
ts->printf(cvtest::TS::LOG, "Wrong hash value \n");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
return;
}
}
}
TEST(marr_hildreth_test, accuracy) { CV_MarrHildrethTest test; test.safe_run(); }
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <bitset>
using namespace cv;
class CV_PHashTest : public cvtest::BaseTest
{
public:
CV_PHashTest();
~CV_PHashTest();
protected:
void run(int /* idx */);
};
CV_PHashTest::CV_PHashTest(){}
CV_PHashTest::~CV_PHashTest(){}
void CV_PHashTest::run(int )
{
cv::Mat input(32, 32, CV_8U);
cv::Mat hash;
uchar value = 0;
uchar *inPtr = input.ptr<uchar>(0);
for(size_t i = 0; i != 32*32; ++i)
{
inPtr[i] = value++;
}
cv::img_hash::pHash(input, hash);
bool const expectResult[] =
{
1,0,1,1,1,1,1,1,
0,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,1,1,1,1,1,1,1,
};
uchar const *hashPtr = hash.ptr<uchar>(0);
for(int i = 0; i != hash.cols; ++i)
{
std::bitset<8> const bits = hashPtr[i];
for(int j = 0; j != 8; ++j)
{
EXPECT_EQ(bits[j], expectResult[i*8+j]);
}
}
}
TEST(average_phash_test, accuracy) { CV_PHashTest test; test.safe_run(); }
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-declarations"
# if defined __clang__ || defined __APPLE__
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
# pragma GCC diagnostic ignored "-Wextra"
# endif
#endif
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include <iostream>
#include "opencv2/ts.hpp"
#include "opencv2/img_hash.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/core/cvdef.h"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#endif
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
using namespace cv;
using namespace cv::img_hash;
/**
*The expected results of this test case are come from the phash library,
*I use it as golden model
*/
class CV_RadialVarianceHashTest : public cvtest::BaseTest
{
public:
CV_RadialVarianceHashTest();
protected:
void run(int /* idx */);
//this test case do not use the original "golden data"
//of pHash library, I add a small value to nb_pixels in
//the function "ph_feature_vector" to avoid NaN value
void testComputeHash();
void testFeatures();
void testHash();
void testPixPerLine();
void testProjection();
cv::Mat input;
Ptr<cv::img_hash::RadialVarianceHash> rvh;
};
CV_RadialVarianceHashTest::CV_RadialVarianceHashTest()
{
input.create(8, 8, CV_8U);
uchar *inPtr = input.ptr<uchar>(0);
for(size_t i = 0; i != input.total(); ++i)
{
inPtr[i] = static_cast<uchar>(i);
}
rvh = RadialVarianceHash::create(1, 10);
}
void CV_RadialVarianceHashTest::testComputeHash()
{
cv::Mat hashOne(1, 40, CV_8U);
uchar buffer[] =
{
52, 41, 49, 64, 40, 67, 76, 71, 69,
55, 58, 68, 72, 78, 63, 73, 66, 77,
60, 57, 48, 59, 62, 74, 70, 47, 46,
51, 45, 44, 42, 61, 54, 75, 50, 79,
65, 43, 53, 56
};
cv::Mat hashTwo(1, 40, CV_8U, buffer);
for(uchar i = 0; i != 40; ++i)
{
hashOne.at<uchar>(0, i) = i;
}
double const actual = rvh->compare(hashOne, hashTwo);
ASSERT_NEAR(0.481051, actual, 0.0001);
}
void CV_RadialVarianceHashTest::testFeatures()
{
std::vector<double> const &features = rvh->getFeatures();
double const expectResult[] =
{-1.35784,-0.42703,0.908487,-1.39327,1.17313,
1.47515,-0.0156121,0.774335,-0.116755,-1.02059};
for(size_t i = 0; i != features.size(); ++i)
{
ASSERT_NEAR(features[i], expectResult[i], 0.0001);
}
}
void CV_RadialVarianceHashTest::testHash()
{
cv::Mat const hash = rvh->getHash();
uchar const expectResult[] =
{
127, 92, 0, 158, 101,
88, 14, 136, 227, 160,
127, 94, 27, 118, 240,
166, 153, 96, 254, 162,
127, 162, 255, 96, 153,
166, 240, 118, 27, 94,
127, 160, 227, 136, 14,
88, 101, 158, 0, 92
};
for(int i = 0; i != hash.cols; ++i)
{
EXPECT_EQ(hash.at<uchar>(0, i), expectResult[i]);
}
}
void CV_RadialVarianceHashTest::testPixPerLine()
{
cv::Mat const pixPerLine = rvh->getPixPerLine(input);
uchar const expectResult[] =
{
8,8,8,0,8,15,7,5,8,8,
};
bool const equal =
std::equal(expectResult, expectResult + pixPerLine.total(),
pixPerLine.ptr<int>(0));
if(equal == false)
{
ts->printf(cvtest::TS::LOG, "Wrong pixel per line value \n");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
}
}
void CV_RadialVarianceHashTest::testProjection()
{
cv::Mat const proj = rvh->getProjection();
uchar const expectResult[] =
{
32, 33, 34, 35, 36, 37, 38, 39,
16, 17, 18, 27, 36, 37, 46, 47,
0, 9, 18, 19, 36, 45, 46, 55,
0, 0, 0, 0, 0, 0, 0, 0,
2, 10, 18, 27, 36, 44, 53, 61,
4, 59, 51, 44, 36, 29, 22, 14,
0, 58, 51, 43, 36, 30, 22, 15,
0, 0, 58, 43, 36, 21, 6, 0,
56, 49, 42, 43, 36, 21, 22, 15,
40, 41, 42, 35, 36, 29, 22, 23
};
bool const equal =
std::equal(expectResult, expectResult + proj.total(),
proj.ptr<uchar>(0));
if(equal == false)
{
ts->printf(cvtest::TS::LOG, "Wrong projection value \n");
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
}
}
void CV_RadialVarianceHashTest::run(int)
{
testPixPerLine();
testProjection();
testFeatures();
testComputeHash();
}
TEST(radial_variance_hash_test, accuracy) { CV_RadialVarianceHashTest test; test.safe_run(); }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment