mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 12:40:05 +08:00
Merge pull request #25122 from unnonouno:pqueue
Use std::priority_queue in inpaint function for performance improvement #25122 In `cv::inpaint` implementation, it uses a priority queue with O(n) time linear search. For large images it is very slow. I replaced it with C++'s standard library `std::priority_queue`, that uses O(log(n)) algorithm. In my use case, it is x10 faster than the original. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
deab144e22
commit
500c55a808
@ -6,6 +6,7 @@ namespace opencv_test
|
||||
CV_ENUM(InpaintingMethod, INPAINT_NS, INPAINT_TELEA)
|
||||
typedef tuple<Size, InpaintingMethod> InpaintArea_InpaintingMethod_t;
|
||||
typedef perf::TestBaseWithParam<InpaintArea_InpaintingMethod_t> InpaintArea_InpaintingMethod;
|
||||
typedef perf::TestBaseWithParam<InpaintingMethod> Perf_InpaintingMethod;
|
||||
|
||||
|
||||
PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint,
|
||||
@ -34,4 +35,26 @@ PERF_TEST_P(InpaintArea_InpaintingMethod, inpaint,
|
||||
SANITY_CHECK(inpaintedArea);
|
||||
}
|
||||
|
||||
PERF_TEST_P(Perf_InpaintingMethod, inpaintDots, InpaintingMethod::all())
|
||||
{
|
||||
Mat src = imread(getDataPath("gpu/hog/road.png"));
|
||||
|
||||
int inpaintingMethod = GetParam();
|
||||
|
||||
Mat mask(src.size(), CV_8UC1, Scalar(0));
|
||||
Mat result(src.size(), src.type());
|
||||
|
||||
for (int i = 0; i < src.size().height; i += 16) {
|
||||
for (int j = 0; j < src.size().width; j += 16) {
|
||||
mask.at<unsigned char>(i, j) = 255;
|
||||
}
|
||||
}
|
||||
|
||||
declare.in(src, mask).out(result).time(120);
|
||||
|
||||
TEST_CYCLE() inpaint(src, mask, result, 10.0, inpaintingMethod);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -45,6 +45,8 @@
|
||||
//
|
||||
// */
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
#include "opencv2/photo/legacy/constants_c.h"
|
||||
@ -71,8 +73,16 @@ typedef struct CvHeapElem
|
||||
{
|
||||
float T;
|
||||
int i,j;
|
||||
struct CvHeapElem* prev;
|
||||
struct CvHeapElem* next;
|
||||
int order; // to keep insertion order
|
||||
|
||||
bool operator > (const CvHeapElem& rhs) const {
|
||||
if (T > rhs.T) {
|
||||
return true;
|
||||
} else if (T < rhs.T) {
|
||||
return false;
|
||||
}
|
||||
return order > rhs.order;
|
||||
}
|
||||
}
|
||||
CvHeapElem;
|
||||
|
||||
@ -84,42 +94,10 @@ private:
|
||||
CvPriorityQueueFloat& operator=(const CvPriorityQueueFloat &); // assign disabled
|
||||
|
||||
protected:
|
||||
CvHeapElem *mem,*empty,*head,*tail;
|
||||
int num,in;
|
||||
std::priority_queue<CvHeapElem, std::vector<CvHeapElem>,std::greater<CvHeapElem> > queue;
|
||||
int next_order;
|
||||
|
||||
public:
|
||||
bool Init( const CvMat* f )
|
||||
{
|
||||
int i,j;
|
||||
for( i = num = 0; i < f->rows; i++ )
|
||||
{
|
||||
for( j = 0; j < f->cols; j++ )
|
||||
num += CV_MAT_ELEM(*f,uchar,i,j)!=0;
|
||||
}
|
||||
if (num<=0) return false;
|
||||
mem = (CvHeapElem*)cvAlloc((num+2)*sizeof(CvHeapElem));
|
||||
if (mem==NULL) return false;
|
||||
|
||||
head = mem;
|
||||
head->i = head->j = -1;
|
||||
head->prev = NULL;
|
||||
head->next = mem+1;
|
||||
head->T = -FLT_MAX;
|
||||
empty = mem+1;
|
||||
for (i=1; i<=num; i++) {
|
||||
mem[i].prev = mem+i-1;
|
||||
mem[i].next = mem+i+1;
|
||||
mem[i].i = -1;
|
||||
mem[i].T = FLT_MAX;
|
||||
}
|
||||
tail = mem+i;
|
||||
tail->i = tail->j = -1;
|
||||
tail->prev = mem+i-1;
|
||||
tail->next = NULL;
|
||||
tail->T = FLT_MAX;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Add(const CvMat* f) {
|
||||
int i,j;
|
||||
for (i=0; i<f->rows; i++) {
|
||||
@ -133,71 +111,33 @@ public:
|
||||
}
|
||||
|
||||
bool Push(int i, int j, float T) {
|
||||
CvHeapElem *tmp=empty,*add=empty;
|
||||
if (empty==tail) return false;
|
||||
while (tmp->prev->T>T) tmp = tmp->prev;
|
||||
if (tmp!=empty) {
|
||||
add->prev->next = add->next;
|
||||
add->next->prev = add->prev;
|
||||
empty = add->next;
|
||||
add->prev = tmp->prev;
|
||||
add->next = tmp;
|
||||
add->prev->next = add;
|
||||
add->next->prev = add;
|
||||
} else {
|
||||
empty = empty->next;
|
||||
}
|
||||
add->i = i;
|
||||
add->j = j;
|
||||
add->T = T;
|
||||
in++;
|
||||
// printf("push i %3d j %3d T %12.4e in %4d\n",i,j,T,in);
|
||||
queue.push({T, i, j, next_order});
|
||||
++next_order;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pop(int *i, int *j) {
|
||||
CvHeapElem *tmp=head->next;
|
||||
if (empty==tmp) return false;
|
||||
*i = tmp->i;
|
||||
*j = tmp->j;
|
||||
tmp->prev->next = tmp->next;
|
||||
tmp->next->prev = tmp->prev;
|
||||
tmp->prev = empty->prev;
|
||||
tmp->next = empty;
|
||||
tmp->prev->next = tmp;
|
||||
tmp->next->prev = tmp;
|
||||
empty = tmp;
|
||||
in--;
|
||||
// printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
|
||||
if (queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
*i = queue.top().i;
|
||||
*j = queue.top().j;
|
||||
queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pop(int *i, int *j, float *T) {
|
||||
CvHeapElem *tmp=head->next;
|
||||
if (empty==tmp) return false;
|
||||
*i = tmp->i;
|
||||
*j = tmp->j;
|
||||
*T = tmp->T;
|
||||
tmp->prev->next = tmp->next;
|
||||
tmp->next->prev = tmp->prev;
|
||||
tmp->prev = empty->prev;
|
||||
tmp->next = empty;
|
||||
tmp->prev->next = tmp;
|
||||
tmp->next->prev = tmp;
|
||||
empty = tmp;
|
||||
in--;
|
||||
// printf("pop i %3d j %3d T %12.4e in %4d\n",tmp->i,tmp->j,tmp->T,in);
|
||||
if (queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
*i = queue.top().i;
|
||||
*j = queue.top().j;
|
||||
*T = queue.top().T;
|
||||
queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
CvPriorityQueueFloat(void) {
|
||||
num=in=0;
|
||||
mem=empty=head=tail=NULL;
|
||||
}
|
||||
|
||||
~CvPriorityQueueFloat(void)
|
||||
{
|
||||
cvFree( &mem );
|
||||
CvPriorityQueueFloat(void) : queue(), next_order() {
|
||||
}
|
||||
};
|
||||
|
||||
@ -786,8 +726,6 @@ icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_
|
||||
cvSet(t,cvScalar(1.0e6f,0,0,0));
|
||||
cv::dilate(cv::cvarrToMat(mask), cv::cvarrToMat(band), el_cross, cv::Point(1, 1));
|
||||
Heap=cv::makePtr<CvPriorityQueueFloat>();
|
||||
if (!Heap->Init(band))
|
||||
return;
|
||||
cvSub(band,mask,band,NULL);
|
||||
SET_BORDER1_C1(band,uchar,0);
|
||||
if (!Heap->Add(band))
|
||||
@ -803,8 +741,6 @@ icvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_
|
||||
cv::dilate(cv::cvarrToMat(mask), cv::cvarrToMat(out), el_range);
|
||||
cvSub(out,mask,out,NULL);
|
||||
Out=cv::makePtr<CvPriorityQueueFloat>();
|
||||
if (!Out->Init(out))
|
||||
return;
|
||||
if (!Out->Add(band))
|
||||
return;
|
||||
cvSub(out,band,out,NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user