From 8d8dc29ced791a2a2de1fe2aada4adfacddbc15e Mon Sep 17 00:00:00 2001 From: yao Date: Wed, 3 Jul 2013 13:13:04 +0800 Subject: [PATCH 1/8] add kmeans --- modules/ocl/include/opencv2/ocl/ocl.hpp | 12 + modules/ocl/src/kmeans.cpp | 471 ++++++++++++++++++++++++ modules/ocl/src/opencl/kmeans_kernel.cl | 83 +++++ modules/ocl/test/test_kmeans.cpp | 162 ++++++++ 4 files changed, 728 insertions(+) create mode 100644 modules/ocl/src/kmeans.cpp create mode 100644 modules/ocl/src/opencl/kmeans_kernel.cl create mode 100644 modules/ocl/test/test_kmeans.cpp diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index fa11177c47..7dcf96fd5a 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -834,6 +834,18 @@ namespace cv CV_EXPORTS void cornerMinEigenVal_dxdy(const oclMat &src, oclMat &dst, oclMat &Dx, oclMat &Dy, int blockSize, int ksize, int bordertype = cv::BORDER_DEFAULT); + /////////////////////////////////// ML /////////////////////////////////////////// + + //! Compute closest centers for each lines in source and lable it after center's index + // supports CV_32FC1/CV_32FC2/CV_32FC4 data type + void DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers); + + //!Does k-means procedure on GPU + // supports CV_32FC1/CV_32FC2/CV_32FC4 data type + CV_EXPORTS double kmeans(const oclMat &src, int K, oclMat &bestLabels, + TermCriteria criteria, int attemps, int flags, oclMat ¢ers); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////CascadeClassifier////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/ocl/src/kmeans.cpp b/modules/ocl/src/kmeans.cpp new file mode 100644 index 0000000000..3922fd8dc8 --- /dev/null +++ b/modules/ocl/src/kmeans.cpp @@ -0,0 +1,471 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Xiaopeng Fu, fuxiaopeng2222@163.com +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other oclMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include +#include "precomp.hpp" + +using namespace cv; +using namespace ocl; + +namespace cv +{ + namespace ocl + { + ////////////////////////////////////OpenCL kernel strings////////////////////////// + extern const char *kmeans_kernel; + } +} +////////////////////////////////////////////////////////////////////////// +//////////////////common///////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// +void swap( Mat& a, Mat& b ) +{ + std::swap(a.flags, b.flags); + std::swap(a.dims, b.dims); + std::swap(a.rows, b.rows); + std::swap(a.cols, b.cols); + std::swap(a.data, b.data); + std::swap(a.refcount, b.refcount); + std::swap(a.datastart, b.datastart); + std::swap(a.dataend, b.dataend); + std::swap(a.datalimit, b.datalimit); + std::swap(a.allocator, b.allocator); + + std::swap(a.size.p, b.size.p); + std::swap(a.step.p, b.step.p); + std::swap(a.step.buf[0], b.step.buf[0]); + std::swap(a.step.buf[1], b.step.buf[1]); + + if( a.step.p == b.step.buf ) + { + a.step.p = a.step.buf; + a.size.p = &a.rows; + } + + if( b.step.p == a.step.buf ) + { + b.step.p = b.step.buf; + b.size.p = &b.rows; + } +} + +static void generateRandomCenter(const vector& box, float* center, RNG& rng) +{ + size_t j, dims = box.size(); + float margin = 1.f/dims; + for( j = 0; j < dims; j++ ) + center[j] = ((float)rng*(1.f+margin*2.f)-margin)*(box[j][1] - box[j][0]) + box[j][0]; +} + +// This class is copied from matrix.cpp in core module. +class KMeansPPDistanceComputer : public ParallelLoopBody +{ +public: + KMeansPPDistanceComputer( float *_tdist2, + const float *_data, + const float *_dist, + int _dims, + size_t _step, + size_t _stepci ) + : tdist2(_tdist2), + data(_data), + dist(_dist), + dims(_dims), + step(_step), + stepci(_stepci) { } + + void operator()( const cv::Range& range ) const + { + const int begin = range.start; + const int end = range.end; + + for ( int i = begin; i _centers(K); + int* centers = &_centers[0]; + vector _dist(N*3); + float* dist = &_dist[0], *tdist = dist + N, *tdist2 = tdist + N; + double sum0 = 0; + + centers[0] = (unsigned)rng % N; + + for( i = 0; i < N; i++ ) + { + dist[i] = normL2Sqr_(data + step*i, data + step*centers[0], dims); + sum0 += dist[i]; + } + + for( k = 1; k < K; k++ ) + { + double bestSum = DBL_MAX; + int bestCenter = -1; + + for( j = 0; j < trials; j++ ) + { + double p = (double)rng*sum0, s = 0; + for( i = 0; i < N-1; i++ ) + if( (p -= dist[i]) <= 0 ) + break; + int ci = i; + + parallel_for_(Range(0, N), + KMeansPPDistanceComputer(tdist2, data, dist, dims, step, step*ci)); + for( i = 0; i < N; i++ ) + { + s += tdist2[i]; + } + + if( s < bestSum ) + { + bestSum = s; + bestCenter = ci; + std::swap(tdist, tdist2); + } + } + centers[k] = bestCenter; + sum0 = bestSum; + std::swap(dist, tdist); + } + + for( k = 0; k < K; k++ ) + { + const float* src = data + step*centers[k]; + float* dst = _out_centers.ptr(k); + for( j = 0; j < dims; j++ ) + dst[j] = src[j]; + } +} + +void cv::ocl::DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers) +{ + //if(src.clCxt -> impl -> double_support == 0 && src.type() == CV_64F) + //{ + // CV_Error(CV_GpuNotSupported, "Selected device don't support double\r\n"); + // return; + //} + + Context *clCxt = src.clCxt; + int labels_step = (int)(labels.step/labels.elemSize()); + string kernelname = "kmeansComputeDistance"; + int threadNum = src.rows > 256 ? 256 : src.rows; + size_t localThreads[3] = {1, threadNum, 1}; + size_t globalThreads[3] = {1, src.rows, 1}; + + vector > args; + args.push_back(make_pair(sizeof(cl_int), (void *)&labels_step)); + args.push_back(make_pair(sizeof(cl_int), (void *)¢ers.rows)); + args.push_back(make_pair(sizeof(cl_mem), (void *)&src.data)); + args.push_back(make_pair(sizeof(cl_mem), (void *)&labels.data)); + args.push_back(make_pair(sizeof(cl_int), (void *)¢ers.cols)); + args.push_back(make_pair(sizeof(cl_int), (void *)&src.rows)); + args.push_back(make_pair(sizeof(cl_mem), (void *)¢ers.data)); + args.push_back(make_pair(sizeof(cl_mem), (void*)&dists.data)); + + openCLExecuteKernel(clCxt, &kmeans_kernel, kernelname, globalThreads, localThreads, args, -1, -1, NULL); +} +///////////////////////////////////k - means ///////////////////////////////////////////////////////// +double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, + TermCriteria criteria, int attempts, int flags, oclMat &_centers) +{ + const int SPP_TRIALS = 3; + bool isrow = _src.rows == 1 && _src.oclchannels() > 1; + int N = !isrow ? _src.rows : _src.cols; + int dims = (!isrow ? _src.cols : 1) * _src.oclchannels(); + int type = _src.depth(); + + attempts = std::max(attempts, 1); + CV_Assert(type == CV_32F && K > 0 ); + CV_Assert( N >= K ); + + Mat _labels; + if( flags & CV_KMEANS_USE_INITIAL_LABELS ) + { + CV_Assert( (_bestLabels.cols == 1 || _bestLabels.rows == 1) && + _bestLabels.cols * _bestLabels.rows == N && + _bestLabels.type() == CV_32S ); + _bestLabels.download(_labels); + } + else + { + if( !((_bestLabels.cols == 1 || _bestLabels.rows == 1) && + _bestLabels.cols * _bestLabels.rows == N && + _bestLabels.type() == CV_32S && + _bestLabels.isContinuous())) + _bestLabels.create(N, 1, CV_32S); + _labels.create(_bestLabels.size(), _bestLabels.type()); + } + int* labels = _labels.ptr(); + + Mat data; + _src.download(data); + Mat centers(K, dims, type), old_centers(K, dims, type), temp(1, dims, type); + vector counters(K); + vector _box(dims); + Vec2f* box = &_box[0]; + double best_compactness = DBL_MAX, compactness = 0; + RNG& rng = theRNG(); + int a, iter, i, j, k; + + if( criteria.type & TermCriteria::EPS ) + criteria.epsilon = std::max(criteria.epsilon, 0.); + else + criteria.epsilon = FLT_EPSILON; + criteria.epsilon *= criteria.epsilon; + + if( criteria.type & TermCriteria::COUNT ) + criteria.maxCount = std::min(std::max(criteria.maxCount, 2), 100); + else + criteria.maxCount = 100; + + if( K == 1 ) + { + attempts = 1; + criteria.maxCount = 2; + } + + const float* sample = data.ptr(); + for( j = 0; j < dims; j++ ) + box[j] = Vec2f(sample[j], sample[j]); + + for( i = 1; i < N; i++ ) + { + sample = data.ptr(i); + for( j = 0; j < dims; j++ ) + { + float v = sample[j]; + box[j][0] = std::min(box[j][0], v); + box[j][1] = std::max(box[j][1], v); + } + } + + for( a = 0; a < attempts; a++ ) + { + double max_center_shift = DBL_MAX; + for( iter = 0;; ) + { + swap(centers, old_centers); + + if( iter == 0 && (a > 0 || !(flags & KMEANS_USE_INITIAL_LABELS)) ) + { + if( flags & KMEANS_PP_CENTERS ) + generateCentersPP(data, centers, K, rng, SPP_TRIALS); + else + { + for( k = 0; k < K; k++ ) + generateRandomCenter(_box, centers.ptr(k), rng); + } + } + else + { + if( iter == 0 && a == 0 && (flags & KMEANS_USE_INITIAL_LABELS) ) + { + for( i = 0; i < N; i++ ) + CV_Assert( (unsigned)labels[i] < (unsigned)K ); + } + + // compute centers + centers = Scalar(0); + for( k = 0; k < K; k++ ) + counters[k] = 0; + + for( i = 0; i < N; i++ ) + { + sample = data.ptr(i); + k = labels[i]; + float* center = centers.ptr(k); + j=0; + #if CV_ENABLE_UNROLLED + for(; j <= dims - 4; j += 4 ) + { + float t0 = center[j] + sample[j]; + float t1 = center[j+1] + sample[j+1]; + + center[j] = t0; + center[j+1] = t1; + + t0 = center[j+2] + sample[j+2]; + t1 = center[j+3] + sample[j+3]; + + center[j+2] = t0; + center[j+3] = t1; + } + #endif + for( ; j < dims; j++ ) + center[j] += sample[j]; + counters[k]++; + } + + if( iter > 0 ) + max_center_shift = 0; + + for( k = 0; k < K; k++ ) + { + if( counters[k] != 0 ) + continue; + + // if some cluster appeared to be empty then: + // 1. find the biggest cluster + // 2. find the farthest from the center point in the biggest cluster + // 3. exclude the farthest point from the biggest cluster and form a new 1-point cluster. + int max_k = 0; + for( int k1 = 1; k1 < K; k1++ ) + { + if( counters[max_k] < counters[k1] ) + max_k = k1; + } + + double max_dist = 0; + int farthest_i = -1; + float* new_center = centers.ptr(k); + float* old_center = centers.ptr(max_k); + float* _old_center = temp.ptr(); // normalized + float scale = 1.f/counters[max_k]; + for( j = 0; j < dims; j++ ) + _old_center[j] = old_center[j]*scale; + + for( i = 0; i < N; i++ ) + { + if( labels[i] != max_k ) + continue; + sample = data.ptr(i); + double dist = normL2Sqr_(sample, _old_center, dims); + + if( max_dist <= dist ) + { + max_dist = dist; + farthest_i = i; + } + } + + counters[max_k]--; + counters[k]++; + labels[farthest_i] = k; + sample = data.ptr(farthest_i); + + for( j = 0; j < dims; j++ ) + { + old_center[j] -= sample[j]; + new_center[j] += sample[j]; + } + } + + for( k = 0; k < K; k++ ) + { + float* center = centers.ptr(k); + CV_Assert( counters[k] != 0 ); + + float scale = 1.f/counters[k]; + for( j = 0; j < dims; j++ ) + center[j] *= scale; + + if( iter > 0 ) + { + double dist = 0; + const float* old_center = old_centers.ptr(k); + for( j = 0; j < dims; j++ ) + { + double t = center[j] - old_center[j]; + dist += t*t; + } + max_center_shift = std::max(max_center_shift, dist); + } + } + } + + if( ++iter == MAX(criteria.maxCount, 2) || max_center_shift <= criteria.epsilon ) + break; + + // assign labels + oclMat _dists(1, N, CV_64F); + + _bestLabels.upload(_labels); + _centers.upload(centers); + DistanceComputer(_dists, _bestLabels, _src, _centers); + + Mat dists; + _dists.download(dists); + _bestLabels.download(_labels); + + double* dist = dists.ptr(0); + compactness = 0; + for( i = 0; i < N; i++ ) + { + compactness += dist[i]; + } + } + + if( compactness < best_compactness ) + { + best_compactness = compactness; + } + } + + return best_compactness; +} + diff --git a/modules/ocl/src/opencl/kmeans_kernel.cl b/modules/ocl/src/opencl/kmeans_kernel.cl new file mode 100644 index 0000000000..d6f6c721a9 --- /dev/null +++ b/modules/ocl/src/opencl/kmeans_kernel.cl @@ -0,0 +1,83 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Xiaopeng Fu, fuxiaopeng2222@163.com +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other GpuMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +__kernel void kmeansComputeDistance( + int label_step, int K, + __global float *src, + __global int *labels, int dims, int rows, + __global float *centers, + __global float *dists) +{ + int gid = get_global_id(1); + + float dist, euDist, min; + int minCentroid; + + if(gid >= rows) + return; + + for(int i = 0 ;i < K; i++) + { + euDist = 0; + for(int j = 0; j < dims; j++) + { + dist = (src[j + gid * dims] + - centers[j + i * dims]); + euDist += dist * dist; + } + + if(i == 0) + { + min = euDist; + minCentroid = 0; + } else if(euDist < min) + { + min = euDist; + minCentroid = i; + } + } + dists[gid] = min; + labels[label_step * gid] = minCentroid; +} diff --git a/modules/ocl/test/test_kmeans.cpp b/modules/ocl/test/test_kmeans.cpp new file mode 100644 index 0000000000..ebade3bbc4 --- /dev/null +++ b/modules/ocl/test/test_kmeans.cpp @@ -0,0 +1,162 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved. +// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// @Authors +// Erping Pang, pang_er_ping@163.com +// Xiaopeng Fu, fuxiaopeng2222@163.com +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other oclMaterials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_OPENCL + +using namespace cvtest; +using namespace testing; +using namespace std; +using namespace cv; + +#define OCL_KMEANS_USE_INITIAL_LABELS 1 +#define OCL_KMEANS_PP_CENTERS 2 + +PARAM_TEST_CASE(Kmeans, int, int, int) +{ + int type; + int K; + int flags; + cv::Mat src ; + ocl::oclMat d_src, d_dists; + + Mat labels, centers; + ocl::oclMat d_labels, d_centers; + cv::RNG rng ; + virtual void SetUp(){ + K = GET_PARAM(0); + type = GET_PARAM(1); + flags = GET_PARAM(2); + rng = TS::ptr()->get_rng(); + + // MWIDTH=256, MHEIGHT=256. defined in utility.hpp + cv::Size size = cv::Size(MWIDTH, MHEIGHT); + src.create(size, type); + int row_idx = 0; + const int max_neighbour = MHEIGHT / K - 1; + CV_Assert(K <= MWIDTH); + for(int i = 0; i < K; i++ ) + { + Mat center_row_header = src.row(row_idx); + center_row_header.setTo(0); + int nchannel = center_row_header.channels(); + for(int j = 0; j < nchannel; j++) + center_row_header.at(0, i*nchannel+j) = 50000.0; + + for(int j = 0; (j < max_neighbour) || + (i == K-1 && j < max_neighbour + MHEIGHT%K); j ++) + { + Mat cur_row_header = src.row(row_idx + 1 + j); + center_row_header.copyTo(cur_row_header); + Mat tmpmat = randomMat(rng, cur_row_header.size(), cur_row_header.type(), -200, 200, false); + cur_row_header += tmpmat; + } + row_idx += 1 + max_neighbour; + } + } +}; +TEST_P(Kmeans, Mat){ + + if(flags & KMEANS_USE_INITIAL_LABELS) + { + // inital a given labels + labels.create(src.rows, 1, CV_32S); + int *label = labels.ptr(); + for(int i = 0; i < src.rows; i++) + label[i] = rng.uniform(0, K); + d_labels.upload(labels); + } + d_src.upload(src); + + for(int j = 0; j < LOOP_TIMES; j++) + { + kmeans(src, K, labels, + TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 100, 0), + 1, flags, centers); + + ocl::kmeans(d_src, K, d_labels, + TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 100, 0), + 1, flags, d_centers); + + Mat dd_labels(d_labels); + Mat dd_centers(d_centers); + if(flags & KMEANS_USE_INITIAL_LABELS) + { + EXPECT_MAT_NEAR(labels, dd_labels, 0); + EXPECT_MAT_NEAR(centers, dd_centers, 1e-3); + } + else + { + int row_idx = 0; + for(int i = 0; i < K; i++) + { + // verify lables with ground truth resutls + int label = labels.at(row_idx); + int header_label = dd_labels.at(row_idx); + for(int j = 0; (j < MHEIGHT/K)||(i == K-1 && j < MHEIGHT/K+MHEIGHT%K); j++) + { + ASSERT_NEAR(labels.at(row_idx+j), label, 0); + ASSERT_NEAR(dd_labels.at(row_idx+j), header_label, 0); + } + + // verify centers + float *center = centers.ptr(label); + float *header_center = dd_centers.ptr(header_label); + for(int t = 0; t < centers.cols; t++) + ASSERT_NEAR(center[t], header_center[t], 1e-3); + + row_idx += MHEIGHT/K; + } + } + } +} +INSTANTIATE_TEST_CASE_P(OCL_ML, Kmeans, Combine( + Values(3, 5, 8), + Values(CV_32FC1, CV_32FC2, CV_32FC4), + Values(OCL_KMEANS_USE_INITIAL_LABELS/*, OCL_KMEANS_PP_CENTERS*/))); + +#endif From a26c4fa2a2bc974f8f8bdd902dce56fc8d0944aa Mon Sep 17 00:00:00 2001 From: Heinz Hofbauer Date: Wed, 3 Jul 2013 14:58:40 +0200 Subject: [PATCH 2/8] Bugfix for an overlapping size of image and template for matchTemplate. Example: img of size 10x10 and templ of size 11x9. In subsequent code this will results in either width or height of corrSize to be zero (0). Line 261 will call crossCorr which will then have a zero size of either blocksize.width or blocksize.height resulting in a division by zero crach in lines 137 or 138. --- modules/imgproc/src/templmatch.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/imgproc/src/templmatch.cpp b/modules/imgproc/src/templmatch.cpp index ec7a92a223..18d7da9d91 100644 --- a/modules/imgproc/src/templmatch.cpp +++ b/modules/imgproc/src/templmatch.cpp @@ -248,6 +248,8 @@ void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, CV_Assert( (img.depth() == CV_8U || img.depth() == CV_32F) && img.type() == templ.type() ); + CV_Assert( img.rows >= templ.rows && img.cols >= templ.cols); + Size corrSize(img.cols - templ.cols + 1, img.rows - templ.rows + 1); _result.create(corrSize, CV_32F); Mat result = _result.getMat(); From c23510785bd61bf4ab287e40d2caca060aa94724 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 4 Jul 2013 08:59:42 +0800 Subject: [PATCH 3/8] remove the redundant function --- modules/ocl/src/kmeans.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/modules/ocl/src/kmeans.cpp b/modules/ocl/src/kmeans.cpp index 3922fd8dc8..e1a91caa5f 100644 --- a/modules/ocl/src/kmeans.cpp +++ b/modules/ocl/src/kmeans.cpp @@ -57,39 +57,6 @@ namespace cv extern const char *kmeans_kernel; } } -////////////////////////////////////////////////////////////////////////// -//////////////////common///////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////// -void swap( Mat& a, Mat& b ) -{ - std::swap(a.flags, b.flags); - std::swap(a.dims, b.dims); - std::swap(a.rows, b.rows); - std::swap(a.cols, b.cols); - std::swap(a.data, b.data); - std::swap(a.refcount, b.refcount); - std::swap(a.datastart, b.datastart); - std::swap(a.dataend, b.dataend); - std::swap(a.datalimit, b.datalimit); - std::swap(a.allocator, b.allocator); - - std::swap(a.size.p, b.size.p); - std::swap(a.step.p, b.step.p); - std::swap(a.step.buf[0], b.step.buf[0]); - std::swap(a.step.buf[1], b.step.buf[1]); - - if( a.step.p == b.step.buf ) - { - a.step.p = a.step.buf; - a.size.p = &a.rows; - } - - if( b.step.p == a.step.buf ) - { - b.step.p = b.step.buf; - b.size.p = &b.rows; - } -} static void generateRandomCenter(const vector& box, float* center, RNG& rng) { From eaa29110e1620aea589b7953e9d29d66a902a2ea Mon Sep 17 00:00:00 2001 From: Alexander Pacha Date: Thu, 4 Jul 2013 16:36:29 +1200 Subject: [PATCH 4/8] Fixed issue 3130 (http://code.opencv.org/issues/3130), where one argument of the BRISK-call was ignored. Previously it was not possible to use BRISK without creating descriptors. Now it behaves like ORB (and how it is documented), and you can call BRISK to just generate feature points and no descriptors. --- modules/features2d/src/brisk.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/features2d/src/brisk.cpp b/modules/features2d/src/brisk.cpp index d1fa0c9c8b..622f772290 100644 --- a/modules/features2d/src/brisk.cpp +++ b/modules/features2d/src/brisk.cpp @@ -525,7 +525,11 @@ BRISK::operator()( InputArray _image, InputArray _mask, vector& keypoi bool doOrientation=true; if (useProvidedKeypoints) doOrientation = false; - computeDescriptorsAndOrOrientation(_image, _mask, keypoints, _descriptors, true, doOrientation, + + // If the user specified cv::noArray(), this will yield false. Otherwise it will return true. + bool doDescriptors = _descriptors.needed(); + + computeDescriptorsAndOrOrientation(_image, _mask, keypoints, _descriptors, doDescriptors, doOrientation, useProvidedKeypoints); } From 88ed74a7ecbfc88b1f394e6cc8b4a20aef5a1f2b Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 5 Jul 2013 08:59:21 +0800 Subject: [PATCH 5/8] fix the function name --- modules/ocl/include/opencv2/ocl/ocl.hpp | 2 +- modules/ocl/src/kmeans.cpp | 36 ++++++++++++------------- modules/ocl/src/opencl/kmeans_kernel.cl | 15 ++++++----- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index 7dcf96fd5a..e7b133e672 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -838,7 +838,7 @@ namespace cv //! Compute closest centers for each lines in source and lable it after center's index // supports CV_32FC1/CV_32FC2/CV_32FC4 data type - void DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers); + CV_EXPORTS void distanceToCenters(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers); //!Does k-means procedure on GPU // supports CV_32FC1/CV_32FC2/CV_32FC4 data type diff --git a/modules/ocl/src/kmeans.cpp b/modules/ocl/src/kmeans.cpp index e1a91caa5f..22f86600a8 100644 --- a/modules/ocl/src/kmeans.cpp +++ b/modules/ocl/src/kmeans.cpp @@ -51,11 +51,11 @@ using namespace ocl; namespace cv { - namespace ocl - { - ////////////////////////////////////OpenCL kernel strings////////////////////////// - extern const char *kmeans_kernel; - } +namespace ocl +{ +////////////////////////////////////OpenCL kernel strings////////////////////////// +extern const char *kmeans_kernel; +} } static void generateRandomCenter(const vector& box, float* center, RNG& rng) @@ -142,7 +142,7 @@ static void generateCentersPP(const Mat& _data, Mat& _out_centers, int ci = i; parallel_for_(Range(0, N), - KMeansPPDistanceComputer(tdist2, data, dist, dims, step, step*ci)); + KMeansPPDistanceComputer(tdist2, data, dist, dims, step, step*ci)); for( i = 0; i < N; i++ ) { s += tdist2[i]; @@ -169,7 +169,7 @@ static void generateCentersPP(const Mat& _data, Mat& _out_centers, } } -void cv::ocl::DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers) +void cv::ocl::distanceToCenters(oclMat &dists, oclMat &labels, const oclMat &src, const oclMat ¢ers) { //if(src.clCxt -> impl -> double_support == 0 && src.type() == CV_64F) //{ @@ -179,7 +179,7 @@ void cv::ocl::DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, Context *clCxt = src.clCxt; int labels_step = (int)(labels.step/labels.elemSize()); - string kernelname = "kmeansComputeDistance"; + string kernelname = "distanceToCenters"; int threadNum = src.rows > 256 ? 256 : src.rows; size_t localThreads[3] = {1, threadNum, 1}; size_t globalThreads[3] = {1, src.rows, 1}; @@ -198,7 +198,7 @@ void cv::ocl::DistanceComputer(oclMat &dists, oclMat &labels, const oclMat &src, } ///////////////////////////////////k - means ///////////////////////////////////////////////////////// double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, - TermCriteria criteria, int attempts, int flags, oclMat &_centers) + TermCriteria criteria, int attempts, int flags, oclMat &_centers) { const int SPP_TRIALS = 3; bool isrow = _src.rows == 1 && _src.oclchannels() > 1; @@ -214,16 +214,16 @@ double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, if( flags & CV_KMEANS_USE_INITIAL_LABELS ) { CV_Assert( (_bestLabels.cols == 1 || _bestLabels.rows == 1) && - _bestLabels.cols * _bestLabels.rows == N && - _bestLabels.type() == CV_32S ); + _bestLabels.cols * _bestLabels.rows == N && + _bestLabels.type() == CV_32S ); _bestLabels.download(_labels); } else { if( !((_bestLabels.cols == 1 || _bestLabels.rows == 1) && - _bestLabels.cols * _bestLabels.rows == N && - _bestLabels.type() == CV_32S && - _bestLabels.isContinuous())) + _bestLabels.cols * _bestLabels.rows == N && + _bestLabels.type() == CV_32S && + _bestLabels.isContinuous())) _bestLabels.create(N, 1, CV_32S); _labels.create(_bestLabels.size(), _bestLabels.type()); } @@ -307,7 +307,7 @@ double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, k = labels[i]; float* center = centers.ptr(k); j=0; - #if CV_ENABLE_UNROLLED +#if CV_ENABLE_UNROLLED for(; j <= dims - 4; j += 4 ) { float t0 = center[j] + sample[j]; @@ -322,7 +322,7 @@ double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, center[j+2] = t0; center[j+3] = t1; } - #endif +#endif for( ; j < dims; j++ ) center[j] += sample[j]; counters[k]++; @@ -410,10 +410,10 @@ double cv::ocl::kmeans(const oclMat &_src, int K, oclMat &_bestLabels, // assign labels oclMat _dists(1, N, CV_64F); - + _bestLabels.upload(_labels); _centers.upload(centers); - DistanceComputer(_dists, _bestLabels, _src, _centers); + distanceToCenters(_dists, _bestLabels, _src, _centers); Mat dists; _dists.download(dists); diff --git a/modules/ocl/src/opencl/kmeans_kernel.cl b/modules/ocl/src/opencl/kmeans_kernel.cl index d6f6c721a9..c6af0ad249 100644 --- a/modules/ocl/src/opencl/kmeans_kernel.cl +++ b/modules/ocl/src/opencl/kmeans_kernel.cl @@ -43,7 +43,7 @@ // //M*/ -__kernel void kmeansComputeDistance( +__kernel void distanceToCenters( int label_step, int K, __global float *src, __global int *labels, int dims, int rows, @@ -51,20 +51,20 @@ __kernel void kmeansComputeDistance( __global float *dists) { int gid = get_global_id(1); - + float dist, euDist, min; int minCentroid; - + if(gid >= rows) return; - for(int i = 0 ;i < K; i++) + for(int i = 0 ; i < K; i++) { euDist = 0; for(int j = 0; j < dims; j++) { - dist = (src[j + gid * dims] - - centers[j + i * dims]); + dist = (src[j + gid * dims] + - centers[j + i * dims]); euDist += dist * dist; } @@ -72,7 +72,8 @@ __kernel void kmeansComputeDistance( { min = euDist; minCentroid = 0; - } else if(euDist < min) + } + else if(euDist < min) { min = euDist; minCentroid = i; From fcb4c0e51c282bee7c0a1319d7ccb2008a5b2c93 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Mon, 8 Jul 2013 21:12:21 +0400 Subject: [PATCH 6/8] fixing working with test data and a small fix for init code - set init value for `numsdev` to prevent use of uninitialized value - stop use of 'workdir' and files from samples - forcing use of 'opencv_extra' instead Note: set OPENCV_TEST_DATA_PATH to full path to 'opencv_extra/testdata' (gitolite@code.opencv.org:opencv_extra.git) before running the test! --- modules/ocl/src/initialization.cpp | 2 +- modules/ocl/test/main.cpp | 5 +---- modules/ocl/test/test_calib3d.cpp | 19 +++++++++---------- modules/ocl/test/test_canny.cpp | 3 +-- modules/ocl/test/test_moments.cpp | 2 +- modules/ocl/test/test_objdetect.cpp | 24 +++++++----------------- modules/ocl/test/test_optflow.cpp | 14 +++++++------- 7 files changed, 27 insertions(+), 42 deletions(-) diff --git a/modules/ocl/src/initialization.cpp b/modules/ocl/src/initialization.cpp index d1ad695ff8..5d81517959 100644 --- a/modules/ocl/src/initialization.cpp +++ b/modules/ocl/src/initialization.cpp @@ -319,7 +319,7 @@ namespace cv char clVersion[256]; for (unsigned i = 0; i < numPlatforms; ++i) { - cl_uint numsdev; + cl_uint numsdev = 0; cl_int status = clGetDeviceIDs(platforms[i], devicetype, 0, NULL, &numsdev); if(status != CL_DEVICE_NOT_FOUND) openCLVerifyCall(status); diff --git a/modules/ocl/test/main.cpp b/modules/ocl/test/main.cpp index 4ba02cf9bc..1250691a1f 100644 --- a/modules/ocl/test/main.cpp +++ b/modules/ocl/test/main.cpp @@ -73,14 +73,12 @@ void print_info() #endif } -std::string workdir; int main(int argc, char **argv) { - TS::ptr()->init("ocl"); + TS::ptr()->init("."); InitGoogleTest(&argc, argv); const char *keys = "{ h | help | false | print help message }" - "{ w | workdir | ../../../samples/c/| set working directory }" "{ t | type | gpu | set device type:cpu or gpu}" "{ p | platform | 0 | set platform id }" "{ d | device | 0 | set device id }"; @@ -92,7 +90,6 @@ int main(int argc, char **argv) cmd.printParams(); return 0; } - workdir = cmd.get("workdir"); string type = cmd.get("type"); unsigned int pid = cmd.get("platform"); int device = cmd.get("device"); diff --git a/modules/ocl/test/test_calib3d.cpp b/modules/ocl/test/test_calib3d.cpp index 14fb31f53a..950f19d3c0 100644 --- a/modules/ocl/test/test_calib3d.cpp +++ b/modules/ocl/test/test_calib3d.cpp @@ -50,7 +50,6 @@ using namespace cv; -extern std::string workdir; PARAM_TEST_CASE(StereoMatchBM, int, int) { int n_disp; @@ -66,9 +65,9 @@ PARAM_TEST_CASE(StereoMatchBM, int, int) TEST_P(StereoMatchBM, Regression) { - Mat left_image = readImage("stereobm/aloe-L.png", IMREAD_GRAYSCALE); - Mat right_image = readImage("stereobm/aloe-R.png", IMREAD_GRAYSCALE); - Mat disp_gold = readImage("stereobm/aloe-disp.png", IMREAD_GRAYSCALE); + Mat left_image = readImage("gpu/stereobm/aloe-L.png", IMREAD_GRAYSCALE); + Mat right_image = readImage("gpu/stereobm/aloe-R.png", IMREAD_GRAYSCALE); + Mat disp_gold = readImage("gpu/stereobm/aloe-disp.png", IMREAD_GRAYSCALE); ocl::oclMat d_left, d_right; ocl::oclMat d_disp(left_image.size(), CV_8U); Mat disp; @@ -113,9 +112,9 @@ PARAM_TEST_CASE(StereoMatchBP, int, int, int, float, float, float, float) }; TEST_P(StereoMatchBP, Regression) { - Mat left_image = readImage("stereobp/aloe-L.png"); - Mat right_image = readImage("stereobp/aloe-R.png"); - Mat disp_gold = readImage("stereobp/aloe-disp.png", IMREAD_GRAYSCALE); + Mat left_image = readImage("gpu/stereobp/aloe-L.png"); + Mat right_image = readImage("gpu/stereobp/aloe-R.png"); + Mat disp_gold = readImage("gpu/stereobp/aloe-disp.png", IMREAD_GRAYSCALE); ocl::oclMat d_left, d_right; ocl::oclMat d_disp; Mat disp; @@ -166,9 +165,9 @@ PARAM_TEST_CASE(StereoMatchConstSpaceBP, int, int, int, int, float, float, float }; TEST_P(StereoMatchConstSpaceBP, Regression) { - Mat left_image = readImage("csstereobp/aloe-L.png"); - Mat right_image = readImage("csstereobp/aloe-R.png"); - Mat disp_gold = readImage("csstereobp/aloe-disp.png", IMREAD_GRAYSCALE); + Mat left_image = readImage("gpu/csstereobp/aloe-L.png"); + Mat right_image = readImage("gpu/csstereobp/aloe-R.png"); + Mat disp_gold = readImage("gpu/csstereobp/aloe-disp.png", IMREAD_GRAYSCALE); ocl::oclMat d_left, d_right; ocl::oclMat d_disp; diff --git a/modules/ocl/test/test_canny.cpp b/modules/ocl/test/test_canny.cpp index 10032e897c..b378b2281b 100644 --- a/modules/ocl/test/test_canny.cpp +++ b/modules/ocl/test/test_canny.cpp @@ -48,7 +48,6 @@ //////////////////////////////////////////////////////// // Canny -extern std::string workdir; IMPLEMENT_PARAM_CLASS(AppertureSize, int); IMPLEMENT_PARAM_CLASS(L2gradient, bool); @@ -67,7 +66,7 @@ PARAM_TEST_CASE(Canny, AppertureSize, L2gradient) TEST_P(Canny, Accuracy) { - cv::Mat img = readImage(workdir + "fruits.jpg", cv::IMREAD_GRAYSCALE); + cv::Mat img = readImage("cv/shared/fruits.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); double low_thresh = 50.0; diff --git a/modules/ocl/test/test_moments.cpp b/modules/ocl/test/test_moments.cpp index 86f4779d68..e3ab1fa3ce 100644 --- a/modules/ocl/test/test_moments.cpp +++ b/modules/ocl/test/test_moments.cpp @@ -45,7 +45,7 @@ TEST_P(MomentsTest, Mat) { if(test_contours) { - Mat src = imread( workdir + "../cpp/pic3.png", IMREAD_GRAYSCALE ); + Mat src = readImage( "cv/shared/pic3.png", IMREAD_GRAYSCALE ); ASSERT_FALSE(src.empty()); Mat canny_output; vector > contours; diff --git a/modules/ocl/test/test_objdetect.cpp b/modules/ocl/test/test_objdetect.cpp index bc719b0974..e9b571e602 100644 --- a/modules/ocl/test/test_objdetect.cpp +++ b/modules/ocl/test/test_objdetect.cpp @@ -63,11 +63,8 @@ PARAM_TEST_CASE(HOG, Size, int) { winSize = GET_PARAM(0); type = GET_PARAM(1); - img_rgb = readImage(workdir + "../gpu/road.png"); - if(img_rgb.empty()) - { - std::cout << "Couldn't read road.png" << std::endl; - } + img_rgb = readImage("gpu/hog/road.png"); + ASSERT_FALSE(img_rgb.empty()); } }; @@ -211,18 +208,11 @@ PARAM_TEST_CASE(Haar, int, CascadeName) virtual void SetUp() { flags = GET_PARAM(0); - cascadeName = (workdir + "../../data/haarcascades/").append(GET_PARAM(1)); - if( (!cascade.load( cascadeName )) || (!cpucascade.load(cascadeName)) ) - { - std::cout << "ERROR: Could not load classifier cascade" << std::endl; - return; - } - img = readImage(workdir + "lena.jpg", IMREAD_GRAYSCALE); - if(img.empty()) - { - std::cout << "Couldn't read lena.jpg" << std::endl; - return ; - } + cascadeName = (string(cvtest::TS::ptr()->get_data_path()) + "cv/cascadeandhog/cascades/").append(GET_PARAM(1)); + ASSERT_TRUE(cascade.load( cascadeName )); + ASSERT_TRUE(cpucascade.load(cascadeName)); + img = readImage("cv/shared/lena.png", IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); equalizeHist(img, img); d_img.upload(img); } diff --git a/modules/ocl/test/test_optflow.cpp b/modules/ocl/test/test_optflow.cpp index 34adb352c2..941ade129e 100644 --- a/modules/ocl/test/test_optflow.cpp +++ b/modules/ocl/test/test_optflow.cpp @@ -75,7 +75,7 @@ PARAM_TEST_CASE(GoodFeaturesToTrack, MinDistance) TEST_P(GoodFeaturesToTrack, Accuracy) { - cv::Mat frame = readImage(workdir + "../gpu/rubberwhale1.png", cv::IMREAD_GRAYSCALE); + cv::Mat frame = readImage("gpu/opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame.empty()); int maxCorners = 1000; @@ -146,10 +146,10 @@ PARAM_TEST_CASE(TVL1, bool) TEST_P(TVL1, Accuracy) { - cv::Mat frame0 = readImage(workdir + "../gpu/rubberwhale1.png", cv::IMREAD_GRAYSCALE); + cv::Mat frame0 = readImage("gpu/opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(workdir + "../gpu/rubberwhale2.png", cv::IMREAD_GRAYSCALE); + cv::Mat frame1 = readImage("gpu/opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); cv::ocl::OpticalFlowDual_TVL1_OCL d_alg; @@ -188,10 +188,10 @@ PARAM_TEST_CASE(Sparse, bool, bool) TEST_P(Sparse, Mat) { - cv::Mat frame0 = readImage(workdir + "../gpu/rubberwhale1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + cv::Mat frame0 = readImage("gpu/opticalflow/rubberwhale1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(workdir + "../gpu/rubberwhale2.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + cv::Mat frame1 = readImage("gpu/opticalflow/rubberwhale2.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); ASSERT_FALSE(frame1.empty()); cv::Mat gray_frame; @@ -301,10 +301,10 @@ PARAM_TEST_CASE(Farneback, PyrScale, PolyN, FarnebackOptFlowFlags, UseInitFlow) TEST_P(Farneback, Accuracy) { - cv::Mat frame0 = imread(workdir + "/rubberwhale1.png", cv::IMREAD_GRAYSCALE); + cv::Mat frame0 = readImage("gpu/opticalflow/rubberwhale1.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = imread(workdir + "/rubberwhale2.png", cv::IMREAD_GRAYSCALE); + cv::Mat frame1 = readImage("gpu/opticalflow/rubberwhale2.png", cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); double polySigma = polyN <= 5 ? 1.1 : 1.5; From f77d1f57eee1a8b9160b5bd2e312736bd6294b9e Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 9 Jul 2013 16:07:55 +0400 Subject: [PATCH 7/8] V4L and V4L2 based Video capture bug fix (Bugfix #3144). --- modules/highgui/src/cap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index cc92da3d0c..0d0fd41ddc 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -220,8 +220,8 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) return capture; break; #endif -#ifdef HAVE_VFW case CV_CAP_VFW: +#ifdef HAVE_VFW capture = cvCreateCameraCapture_VFW (index); if (capture) return capture; From 2b2e02166ef81973e040ff36e9812d8e83599380 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Wed, 10 Jul 2013 15:12:39 +0400 Subject: [PATCH 8/8] setting version to 2.4.6.1 (hot-fix release for Linux camera support) --- modules/core/include/opencv2/core/version.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp index 0a7760873c..ba71a82592 100644 --- a/modules/core/include/opencv2/core/version.hpp +++ b/modules/core/include/opencv2/core/version.hpp @@ -50,7 +50,7 @@ #define CV_VERSION_EPOCH 2 #define CV_VERSION_MAJOR 4 #define CV_VERSION_MINOR 6 -#define CV_VERSION_REVISION 0 +#define CV_VERSION_REVISION 1 #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A)