Merge pull request #239 from sbokov/disparityFiltering
Interface and demo for disparity filtering, basic WLS implementationpull/180/head
commit
844c30e8b2
6 changed files with 831 additions and 1 deletions
@ -1,5 +1,5 @@ |
||||
set(the_description "Extended image processing module. It includes edge-aware filters and etc.") |
||||
set(OPENCV_MODULE_IS_PART_OF_WORLD OFF) |
||||
ocv_define_module(ximgproc opencv_imgproc opencv_core opencv_highgui WRAP python) |
||||
ocv_define_module(ximgproc opencv_imgproc opencv_core opencv_highgui opencv_calib3d WRAP python) |
||||
|
||||
target_link_libraries(opencv_ximgproc) |
||||
|
@ -0,0 +1,92 @@ |
||||
/*
|
||||
* 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 |
||||
* (3 - clause BSD License) |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
* |
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
* |
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may 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 copyright holders 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. |
||||
*/ |
||||
|
||||
#ifndef __OPENCV_DISPARITYFILTER_HPP__ |
||||
#define __OPENCV_DISPARITYFILTER_HPP__ |
||||
#ifdef __cplusplus |
||||
|
||||
#include <opencv2/core.hpp> |
||||
|
||||
namespace cv { |
||||
namespace ximgproc { |
||||
|
||||
class CV_EXPORTS_W DisparityFilter : public Algorithm |
||||
{ |
||||
public: |
||||
CV_WRAP virtual void filter(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map,Rect ROI) = 0; |
||||
}; |
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CV_EXPORTS_W DisparityDTFilter : public DisparityFilter |
||||
{ |
||||
public: |
||||
CV_WRAP virtual double getSigmaSpatial() = 0; |
||||
CV_WRAP virtual void setSigmaSpatial(double _sigmaSpatial) = 0; |
||||
CV_WRAP virtual double getSigmaColor() = 0; |
||||
CV_WRAP virtual void setSigmaColor(double _sigmaColor) = 0; |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityDTFilter> createDisparityDTFilter(); |
||||
|
||||
class CV_EXPORTS_W DisparityGuidedFilter : public DisparityFilter |
||||
{ |
||||
public: |
||||
CV_WRAP virtual double getEps() = 0; |
||||
CV_WRAP virtual void setEps(double _eps) = 0; |
||||
CV_WRAP virtual int getRadius() = 0; |
||||
CV_WRAP virtual void setRadius(int _radius) = 0; |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityGuidedFilter> createDisparityGuidedFilter(); |
||||
|
||||
class CV_EXPORTS_W DisparityWLSFilter : public DisparityFilter |
||||
{ |
||||
CV_WRAP virtual double getLambda() = 0; |
||||
CV_WRAP virtual void setLambda(double _lambda) = 0; |
||||
CV_WRAP virtual double getSigmaColor() = 0; |
||||
CV_WRAP virtual void setSigmaColor(double _sigma_color) = 0; |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityWLSFilter> createDisparityWLSFilter(); |
||||
|
||||
} |
||||
} |
||||
#endif |
||||
#endif |
@ -0,0 +1,258 @@ |
||||
#include "opencv2/calib3d.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/imgcodecs.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include "opencv2/core/utility.hpp" |
||||
#include "opencv2/ximgproc/disparity_filter.hpp" |
||||
#include <stdio.h> |
||||
#include <string> |
||||
#include <vector> |
||||
#include <map> |
||||
|
||||
#if defined(_WIN32) |
||||
#include <direct.h> |
||||
#else |
||||
#include <sys/stat.h> |
||||
#endif |
||||
|
||||
using namespace cv; |
||||
using namespace cv::ximgproc; |
||||
using namespace std; |
||||
|
||||
#define UNKNOWN_DISPARITY 16320 |
||||
|
||||
static void print_help() |
||||
{ |
||||
printf("\nDemo for disparity filtering, evaluating speed and performance of different filters\n"); |
||||
printf("\nUsage: disparity_filtering.exe <path_to_dataset_folder> <path_to_results_folder>\n"); |
||||
} |
||||
|
||||
struct dataset_entry |
||||
{ |
||||
string name; |
||||
string dataset_folder; |
||||
string left_file,right_file,GT_file; |
||||
dataset_entry(string _dataset_folder): dataset_folder(_dataset_folder){} |
||||
void readEntry(Mat& dst_left,Mat& dst_right,Mat& dst_GT) |
||||
{ |
||||
dst_left = imread(dataset_folder+"/"+left_file, IMREAD_COLOR); |
||||
dst_right = imread(dataset_folder+"/"+right_file, IMREAD_COLOR); |
||||
Mat raw_disp = imread(dataset_folder+"/"+GT_file, IMREAD_COLOR); |
||||
dst_GT = Mat(raw_disp.rows,raw_disp.cols,CV_16S); |
||||
for(int i=0;i<raw_disp.rows;i++) |
||||
for(int j=0;j<raw_disp.cols;j++) |
||||
{ |
||||
Vec3b bgrPixel = raw_disp.at<Vec3b>(i, j); |
||||
dst_GT.at<short>(i,j) = 64*bgrPixel.val[2]+bgrPixel.val[1]/4; //16-multiplied disparity
|
||||
} |
||||
} |
||||
}; |
||||
|
||||
struct config |
||||
{ |
||||
Ptr<StereoMatcher> matcher_instance; |
||||
Ptr<DisparityFilter> filter_instance; |
||||
config(Ptr<StereoMatcher> _matcher_instance,Ptr<DisparityFilter> _filter_instance) |
||||
{ |
||||
matcher_instance = _matcher_instance; |
||||
filter_instance = _filter_instance; |
||||
} |
||||
config() {} |
||||
}; |
||||
|
||||
void operator>>(const FileNode& node,dataset_entry& entry); |
||||
double computeMSE(Mat& GT, Mat& src, Rect ROI); |
||||
double computeBadPixelPercent(Mat& GT, Mat& src, Rect ROI, int thresh=24/*1.5 pixels*/); |
||||
void getDisparityVis(Mat& disparity_map,Mat& dst); |
||||
Rect computeROI(Size2i src_sz, Ptr<StereoMatcher> matcher_instance); |
||||
void setConfigsForTesting(map<string,config>& cfgs); |
||||
void CreateDir(string path); |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
if(argc < 3) |
||||
{ |
||||
print_help(); |
||||
return 0; |
||||
} |
||||
string dataset_folder(argv[1]); |
||||
string res_folder(argv[2]); |
||||
|
||||
map<string,config> configs_for_testing; |
||||
setConfigsForTesting(configs_for_testing); |
||||
CreateDir(res_folder); |
||||
|
||||
for (map<string,config>::iterator cfg = configs_for_testing.begin(); cfg != configs_for_testing.end(); cfg++) |
||||
{ |
||||
string vis_folder = res_folder+"/vis_"+cfg->first; |
||||
CreateDir(vis_folder); |
||||
|
||||
string cfg_file_name = res_folder+"/"+cfg->first+"_res.csv"; |
||||
FILE* cur_cfg_res_file = fopen(cfg_file_name.c_str(),"w"); |
||||
fprintf(cur_cfg_res_file,"Name,MSE,MSE after postfiltering,Percent bad,Percent bad after postfiltering,Matcher Execution Time(s),Filter Execution Time(s)\n"); |
||||
|
||||
printf("Processing configuration: %s\n",cfg->first.c_str()); |
||||
|
||||
FileStorage fs(dataset_folder + "/_dataset.xml", FileStorage::READ); |
||||
FileNode n = fs["data_set"]; |
||||
double MSE_pre,percent_pre,MSE_post,percent_post,matching_time,filtering_time; |
||||
double average_MSE_pre=0,average_percent_pre=0,average_MSE_post=0, |
||||
average_percent_post=0,average_matching_time=0,average_filtering_time=0; |
||||
int cnt = 0; |
||||
for (FileNodeIterator it = n.begin(); it != n.end(); it++) |
||||
{ |
||||
dataset_entry entry(dataset_folder); |
||||
(*it)>>entry; |
||||
printf("%s ",entry.name.c_str()); |
||||
Mat left,right,GT; |
||||
entry.readEntry(left,right,GT); |
||||
Mat raw_disp; |
||||
Mat left_gray; cvtColor(left, left_gray, COLOR_BGR2GRAY ); |
||||
Mat right_gray; cvtColor(right, right_gray, COLOR_BGR2GRAY ); |
||||
matching_time = (double)getTickCount(); |
||||
cfg->second.matcher_instance->compute(left_gray,right_gray,raw_disp); |
||||
matching_time = ((double)getTickCount() - matching_time)/getTickFrequency(); |
||||
|
||||
Rect ROI = computeROI(left.size(),cfg->second.matcher_instance); |
||||
Mat filtered_disp; |
||||
filtering_time = (double)getTickCount(); |
||||
cfg->second.filter_instance->filter(raw_disp,left,filtered_disp,ROI); |
||||
filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency(); |
||||
|
||||
|
||||
MSE_pre = computeMSE(GT,raw_disp,ROI); |
||||
percent_pre = computeBadPixelPercent(GT,raw_disp,ROI); |
||||
MSE_post = computeMSE(GT,filtered_disp,ROI); |
||||
percent_post = computeBadPixelPercent(GT,filtered_disp,ROI); |
||||
|
||||
fprintf(cur_cfg_res_file,"%s,%.1f,%.1f,%.1f,%.1f,%.3f,%.3f\n",entry.name.c_str(),MSE_pre,MSE_post, |
||||
percent_pre,percent_post,matching_time,filtering_time); |
||||
|
||||
average_matching_time+=matching_time; average_filtering_time+=filtering_time; |
||||
average_MSE_pre+=MSE_pre; average_percent_pre+=percent_pre; |
||||
average_MSE_post+=MSE_post; average_percent_post+=percent_post; |
||||
cnt++; |
||||
|
||||
// dump visualizations:
|
||||
imwrite(vis_folder + "/" + entry.name + "_left.png",left); |
||||
Mat GT_vis,raw_disp_vis,filtered_disp_vis; |
||||
getDisparityVis(GT,GT_vis); |
||||
getDisparityVis(raw_disp,raw_disp_vis); |
||||
getDisparityVis(filtered_disp,filtered_disp_vis); |
||||
imwrite(vis_folder + "/" + entry.name + "_disparity_GT.png",GT_vis); |
||||
imwrite(vis_folder + "/" + entry.name + "_disparity_raw.png",raw_disp_vis); |
||||
imwrite(vis_folder + "/" + entry.name + "_disparity_filtered.png",filtered_disp_vis); |
||||
|
||||
printf("- Done\n"); |
||||
|
||||
} |
||||
fprintf(cur_cfg_res_file,"%s,%.1f,%.1f,%.1f,%.1f,%.3f,%.3f\n","average",average_MSE_pre/cnt, |
||||
average_MSE_post/cnt,average_percent_pre/cnt,average_percent_post/cnt, |
||||
average_matching_time/cnt,average_filtering_time/cnt); |
||||
fclose(cur_cfg_res_file); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void operator>>(const FileNode& node,dataset_entry& entry)
|
||||
{ |
||||
node["name"] >> entry.name; |
||||
node["left_file"] >> entry.left_file; |
||||
node["right_file"] >> entry.right_file; |
||||
node["GT_file"] >> entry.GT_file; |
||||
} |
||||
|
||||
double computeMSE(Mat& GT, Mat& src, Rect ROI) |
||||
{ |
||||
double res = 0; |
||||
Mat GT_ROI(GT,ROI); |
||||
Mat src_ROI(src,ROI); |
||||
int cnt=0; |
||||
for(int i=0;i<src_ROI.rows;i++) |
||||
for(int j=0;j<src_ROI.cols;j++) |
||||
{ |
||||
if(GT_ROI.at<short>(i,j)!=UNKNOWN_DISPARITY) |
||||
{ |
||||
res += (GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j))*(GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j)); |
||||
cnt++; |
||||
} |
||||
} |
||||
res /= cnt*256; |
||||
return res; |
||||
} |
||||
|
||||
double computeBadPixelPercent(Mat& GT, Mat& src, Rect ROI, int thresh) |
||||
{ |
||||
int bad_pixel_num = 0; |
||||
Mat GT_ROI(GT,ROI); |
||||
Mat src_ROI(src,ROI); |
||||
int cnt=0; |
||||
for(int i=0;i<src_ROI.rows;i++) |
||||
for(int j=0;j<src_ROI.cols;j++) |
||||
{ |
||||
if(GT_ROI.at<short>(i,j)!=UNKNOWN_DISPARITY) |
||||
{ |
||||
if( abs(GT_ROI.at<short>(i,j) - src_ROI.at<short>(i,j))>=thresh ) |
||||
bad_pixel_num++; |
||||
cnt++; |
||||
} |
||||
} |
||||
return (100.0*bad_pixel_num)/cnt; |
||||
} |
||||
|
||||
void getDisparityVis(Mat& disparity_map,Mat& dst) |
||||
{ |
||||
dst = Mat(disparity_map.rows,disparity_map.cols,CV_8UC3); |
||||
for(int i=0;i<dst.rows;i++) |
||||
for(int j=0;j<dst.cols;j++) |
||||
{ |
||||
if(disparity_map.at<short>(i,j)==UNKNOWN_DISPARITY) |
||||
dst.at<Vec3b>(i,j) = Vec3b(0,0,0); |
||||
else |
||||
dst.at<Vec3b>(i,j) = Vec3b(saturate_cast<unsigned char>(disparity_map.at<short>(i,j)/8), |
||||
saturate_cast<unsigned char>(disparity_map.at<short>(i,j)/8), |
||||
saturate_cast<unsigned char>(disparity_map.at<short>(i,j)/8)); |
||||
} |
||||
} |
||||
|
||||
Rect computeROI(Size2i src_sz, Ptr<StereoMatcher> matcher_instance) |
||||
{ |
||||
int min_disparity = matcher_instance->getMinDisparity(); |
||||
int num_disparities = matcher_instance->getNumDisparities(); |
||||
int block_size = matcher_instance->getBlockSize(); |
||||
|
||||
int bs2 = block_size/2; |
||||
int minD = min_disparity, maxD = min_disparity + num_disparities - 1; |
||||
|
||||
int xmin = maxD + bs2; |
||||
int xmax = src_sz.width - minD - bs2; |
||||
int ymin = bs2; |
||||
int ymax = src_sz.height - bs2; |
||||
|
||||
Rect r(xmin, ymin, xmax - xmin, ymax - ymin); |
||||
return r; |
||||
} |
||||
|
||||
void setConfigsForTesting(map<string,config>& cfgs) |
||||
{ |
||||
Ptr<StereoBM> stereobm_matcher = StereoBM::create(128,21);
|
||||
stereobm_matcher->setTextureThreshold(0);
|
||||
stereobm_matcher->setUniquenessRatio(0); |
||||
|
||||
Ptr<DisparityFilter> wls_filter = createDisparityWLSFilter(); |
||||
Ptr<DisparityFilter> dt_filter = createDisparityDTFilter(); |
||||
Ptr<DisparityFilter> guided_filter = createDisparityGuidedFilter(); |
||||
|
||||
cfgs["stereobm_wls"] = config(stereobm_matcher,wls_filter); |
||||
cfgs["stereobm_dtf"] = config(stereobm_matcher,dt_filter); |
||||
cfgs["stereobm_gf"] = config(stereobm_matcher,guided_filter); |
||||
} |
||||
|
||||
void CreateDir(string path) |
||||
{ |
||||
#if defined(_WIN32) |
||||
_mkdir(path.c_str()); |
||||
#else |
||||
mkdir(path.c_str(), 0777); |
||||
#endif |
||||
} |
@ -0,0 +1,185 @@ |
||||
/*
|
||||
* 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 |
||||
* (3 - clause BSD License) |
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
*
|
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
*
|
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may 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 copyright holders 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. |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
#include "opencv2/ximgproc/disparity_filter.hpp" |
||||
#include <math.h> |
||||
|
||||
namespace cv { |
||||
namespace ximgproc { |
||||
|
||||
void setROI(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map, |
||||
Mat& disp,Mat& src,Mat& dst,Rect ROI); |
||||
|
||||
class DisparityDTFilterImpl : public DisparityDTFilter |
||||
{ |
||||
protected: |
||||
double sigmaSpatial,sigmaColor; |
||||
void init(double _sigmaSpatial, double _sigmaColor) |
||||
{ |
||||
sigmaColor = _sigmaColor; |
||||
sigmaSpatial = _sigmaSpatial; |
||||
} |
||||
public: |
||||
double getSigmaSpatial() {return sigmaSpatial;} |
||||
void setSigmaSpatial(double _sigmaSpatial) {sigmaSpatial = _sigmaSpatial;} |
||||
double getSigmaColor() {return sigmaColor;} |
||||
void setSigmaColor(double _sigmaColor) {sigmaColor = _sigmaColor;} |
||||
|
||||
static Ptr<DisparityDTFilterImpl> create() |
||||
{ |
||||
DisparityDTFilterImpl *dtf = new DisparityDTFilterImpl(); |
||||
dtf->init(25.0,60.0);
|
||||
return Ptr<DisparityDTFilterImpl>(dtf); |
||||
} |
||||
|
||||
void filter(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map,Rect ROI) |
||||
{ |
||||
Mat disp,src,dst; |
||||
setROI(disparity_map,left_view,filtered_disparity_map,disp,src,dst,ROI); |
||||
|
||||
Mat disp_32F,dst_32F; |
||||
disp.convertTo(disp_32F,CV_32F); |
||||
dtFilter(src,disp_32F,dst_32F,sigmaSpatial,sigmaColor); |
||||
dst_32F.convertTo(dst,CV_16S); |
||||
} |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityDTFilter> createDisparityDTFilter() |
||||
{ |
||||
return Ptr<DisparityDTFilter>(DisparityDTFilterImpl::create()); |
||||
} |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DisparityGuidedFilterImpl : public DisparityGuidedFilter |
||||
{ |
||||
protected: |
||||
int radius; |
||||
double eps; |
||||
void init(int _radius, double _eps) |
||||
{ |
||||
radius = _radius; |
||||
eps = _eps; |
||||
} |
||||
public: |
||||
double getEps() {return eps;} |
||||
void setEps(double _eps) {eps = _eps;} |
||||
int getRadius() {return radius;} |
||||
void setRadius(int _radius) {radius = _radius;} |
||||
|
||||
static Ptr<DisparityGuidedFilterImpl> create() |
||||
{ |
||||
DisparityGuidedFilterImpl *gf = new DisparityGuidedFilterImpl(); |
||||
gf->init(20,100.0); |
||||
return Ptr<DisparityGuidedFilterImpl>(gf); |
||||
} |
||||
|
||||
void filter(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map,Rect ROI) |
||||
{ |
||||
Mat disp,src,dst; |
||||
setROI(disparity_map,left_view,filtered_disparity_map,disp,src,dst,ROI); |
||||
|
||||
Mat disp_32F,dst_32F; |
||||
disp.convertTo(disp_32F,CV_32F); |
||||
guidedFilter(src,disp_32F,dst_32F,radius,eps); |
||||
dst_32F.convertTo(dst,CV_16S); |
||||
} |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityGuidedFilter> createDisparityGuidedFilter() |
||||
{ |
||||
return Ptr<DisparityGuidedFilter>(DisparityGuidedFilterImpl::create()); |
||||
} |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DisparityWLSFilterImpl : public DisparityWLSFilter |
||||
{ |
||||
protected: |
||||
double lambda,sigma_color; |
||||
void init(double _lambda, double _sigma_color) |
||||
{ |
||||
lambda = _lambda; |
||||
sigma_color = _sigma_color; |
||||
} |
||||
public: |
||||
double getLambda() {return lambda;} |
||||
void setLambda(double _lambda) {lambda = _lambda;} |
||||
double getSigmaColor() {return sigma_color;} |
||||
void setSigmaColor(double _sigma_color) {sigma_color = _sigma_color;} |
||||
|
||||
static Ptr<DisparityWLSFilterImpl> create() |
||||
{ |
||||
DisparityWLSFilterImpl *wls = new DisparityWLSFilterImpl(); |
||||
wls->init(500.0,2.0); |
||||
return Ptr<DisparityWLSFilterImpl>(wls); |
||||
} |
||||
|
||||
void filter(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map,Rect ROI) |
||||
{ |
||||
Mat disp,src,dst; |
||||
setROI(disparity_map,left_view,filtered_disparity_map,disp,src,dst,ROI); |
||||
weightedLeastSquaresFilter(src,disp,dst,lambda,sigma_color); |
||||
} |
||||
}; |
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<DisparityWLSFilter> createDisparityWLSFilter() |
||||
{ |
||||
return Ptr<DisparityWLSFilter>(DisparityWLSFilterImpl::create()); |
||||
} |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setROI(InputArray disparity_map, InputArray left_view, OutputArray filtered_disparity_map, |
||||
Mat& disp,Mat& src,Mat& dst,Rect ROI) |
||||
{ |
||||
Mat disp_full_size = disparity_map.getMat(); |
||||
Mat src_full_size = left_view.getMat(); |
||||
CV_Assert( (disp_full_size.depth() == CV_16S) && (disp_full_size.channels() == 1) ); |
||||
CV_Assert( (src_full_size.depth() == CV_8U) && (src_full_size.channels() <= 4) ); |
||||
disp = Mat(disp_full_size,ROI); |
||||
src = Mat(src_full_size ,ROI); |
||||
filtered_disparity_map.create(disp_full_size.size(), disp_full_size.type()); |
||||
Mat& dst_full_size = filtered_disparity_map.getMatRef(); |
||||
dst = Mat(dst_full_size,ROI); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,284 @@ |
||||
/*
|
||||
* 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 |
||||
* (3 - clause BSD License) |
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, |
||||
* are permitted provided that the following conditions are met : |
||||
*
|
||||
* *Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, |
||||
* this list of conditions and the following disclaimer in the documentation |
||||
* and / or other materials provided with the distribution. |
||||
*
|
||||
* * Neither the names of the copyright holders nor the names of the contributors |
||||
* may 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 copyright holders 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. |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
namespace cv { |
||||
namespace ximgproc { |
||||
|
||||
class WeightedLeastSquaresFilterImpl : public WeightedLeastSquaresFilter |
||||
{ |
||||
public: |
||||
static Ptr<WeightedLeastSquaresFilterImpl> create(InputArray guide, double lambda, double sigma_color, int num_iter); |
||||
void filter(InputArray src, OutputArray dst); |
||||
~WeightedLeastSquaresFilterImpl(); |
||||
protected: |
||||
int w,h; |
||||
double sigmaColor,lambda; |
||||
int num_iter; |
||||
double *weights_LUT; |
||||
double *Ahor, *Bhor, *Chor,
|
||||
*Avert, *Bvert, *Cvert; |
||||
double *interD,*interE,*cur_res; |
||||
void init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter); |
||||
void buildCoefMatrices(Mat& guide); |
||||
void horizontalPass(double* cur); |
||||
void verticalPass(double* cur); |
||||
}; |
||||
|
||||
void WeightedLeastSquaresFilterImpl::init(InputArray guide,double _lambda,double _sigmaColor,int _num_iter) |
||||
{ |
||||
//currently support only 3 channel 8bit images as guides
|
||||
CV_Assert( !guide.empty() && _lambda >= 0 && _sigmaColor >= 0 && _num_iter >=1 ); |
||||
CV_Assert( guide.depth() == CV_8U && guide.channels() == 3 ); |
||||
sigmaColor = _sigmaColor; |
||||
lambda = _lambda; |
||||
num_iter = _num_iter; |
||||
int num_levels = 3*256*256; |
||||
weights_LUT = new double[num_levels]; |
||||
for(int i=0;i<num_levels;i++) |
||||
weights_LUT[i] = exp(-sqrt((double)i)/sigmaColor); |
||||
w = guide.cols(); |
||||
h = guide.rows(); |
||||
int sz = w*h; |
||||
Ahor = new double[sz];Bhor = new double[sz];Chor = new double[sz]; |
||||
Avert = new double[sz];Bvert = new double[sz];Cvert = new double[sz]; |
||||
interD = new double[sz];interE = new double[sz];cur_res = new double[sz]; |
||||
Mat guideMat = guide.getMat(); |
||||
buildCoefMatrices(guideMat); |
||||
} |
||||
|
||||
Ptr<WeightedLeastSquaresFilterImpl> WeightedLeastSquaresFilterImpl::create(InputArray guide, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
WeightedLeastSquaresFilterImpl *wls = new WeightedLeastSquaresFilterImpl(); |
||||
wls->init(guide,lambda,sigma_color,num_iter); |
||||
return Ptr<WeightedLeastSquaresFilterImpl>(wls); |
||||
} |
||||
|
||||
WeightedLeastSquaresFilter::~WeightedLeastSquaresFilter(){} |
||||
WeightedLeastSquaresFilterImpl::~WeightedLeastSquaresFilterImpl() |
||||
{ |
||||
delete[] weights_LUT; |
||||
delete[] Ahor; delete[] Bhor; delete[] Chor; |
||||
delete[] Avert; delete[] Bvert; delete[] Cvert; |
||||
delete[] interD;delete[] interE;delete[] cur_res; |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::buildCoefMatrices(Mat& guide) |
||||
{ |
||||
double hor_weight; |
||||
const unsigned char *row,*row_prev,*row_next; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
//compute horizontal coefs:
|
||||
row = guide.ptr(i); |
||||
Ahor[i*w] = 0; |
||||
hor_weight = weights_LUT[ (row[0]-row[3])*(row[0]-row[3])+ |
||||
(row[1]-row[4])*(row[1]-row[4])+ |
||||
(row[2]-row[5])*(row[2]-row[5]) ]; |
||||
Chor[i*w] = -lambda*hor_weight; |
||||
Bhor[i*w] = 1 - Ahor[i*w] - Chor[i*w]; |
||||
row+=3; |
||||
for(int j=1;j<w-1;j++) |
||||
{ |
||||
Ahor[i*w+j] = -lambda*hor_weight; |
||||
hor_weight = weights_LUT[ (row[0]-row[3])*(row[0]-row[3])+ |
||||
(row[1]-row[4])*(row[1]-row[4])+ |
||||
(row[2]-row[5])*(row[2]-row[5]) ]; |
||||
Chor[i*w+j] = -lambda*hor_weight; |
||||
Bhor[i*w+j] = 1 - Ahor[i*w+j] - Chor[i*w+j]; |
||||
row+=3; |
||||
} |
||||
Ahor[i*w+w-1] = -lambda*hor_weight; |
||||
Chor[i*w+w-1] = 0; |
||||
Bhor[i*w+w-1] = 1 - Ahor[i*w+w-1] - Chor[i*w+w-1]; |
||||
|
||||
//compute vertical coefs:
|
||||
row = guide.ptr(i); |
||||
if(i==0) |
||||
{ |
||||
row_next = guide.ptr(i+1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = 0; |
||||
Cvert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_next[0])*(row[0]-row_next[0])+ |
||||
(row[1]-row_next[1])*(row[1]-row_next[1])+ |
||||
(row[2]-row_next[2])*(row[2]-row_next[2]) ]; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_next+=3; |
||||
} |
||||
} |
||||
else if(i==h-1) |
||||
{ |
||||
row_prev = guide.ptr(i-1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_prev[0])*(row[0]-row_prev[0])+ |
||||
(row[1]-row_prev[1])*(row[1]-row_prev[1])+ |
||||
(row[2]-row_prev[2])*(row[2]-row_prev[2]) ]; |
||||
Cvert[i*w+j] = 0; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_prev+=3; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
row_prev = guide.ptr(i-1); |
||||
row_next = guide.ptr(i+1); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
Avert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_prev[0])*(row[0]-row_prev[0])+ |
||||
(row[1]-row_prev[1])*(row[1]-row_prev[1])+ |
||||
(row[2]-row_prev[2])*(row[2]-row_prev[2]) ]; |
||||
Cvert[i*w+j] = -lambda*weights_LUT[ (row[0]-row_next[0])*(row[0]-row_next[0])+ |
||||
(row[1]-row_next[1])*(row[1]-row_next[1])+ |
||||
(row[2]-row_next[2])*(row[2]-row_next[2]) ]; |
||||
Bvert[i*w+j] = 1 - Avert[i*w+j] - Cvert[i*w+j]; |
||||
row+=3; |
||||
row_prev+=3; |
||||
row_next+=3; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::filter(InputArray src, OutputArray dst) |
||||
{ |
||||
//temporarily support only one-channel CV_16S src type (for disparity map filtering)
|
||||
CV_Assert(!src.empty() && (src.depth() == CV_16S) && src.channels()==1); |
||||
if (src.rows() != h || src.cols() != w) |
||||
{ |
||||
CV_Error(Error::StsBadSize, "Size of filtering image must be equal to size of guide image"); |
||||
return; |
||||
} |
||||
|
||||
Mat srcMat = src.getMat();
|
||||
Mat& dstMat = dst.getMatRef(); |
||||
short* row; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
row = (short*)srcMat.ptr(i); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
cur_res[i*w+j] = (double)(*row); |
||||
row++; |
||||
} |
||||
} |
||||
|
||||
for(int n=0;n<num_iter;n++) |
||||
{ |
||||
horizontalPass(cur_res); |
||||
verticalPass(cur_res); |
||||
} |
||||
|
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
row = (short*)dstMat.ptr(i); |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
*row = saturate_cast<short>(cur_res[i*w+j]); |
||||
row++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::horizontalPass(double* cur) |
||||
{ |
||||
double denom; |
||||
for(int i=0;i<h;i++) |
||||
{ |
||||
//forward pass:
|
||||
interD[i*w] = Chor[i*w]/Bhor[i*w]; |
||||
interE[i*w] = cur[i*w] /Bhor[i*w]; |
||||
for(int j=1;j<w;j++) |
||||
{ |
||||
denom = Bhor[i*w+j]-interD[i*w+j-1]*Ahor[i*w+j]; |
||||
interD[i*w+j] = Chor[i*w+j]/denom; |
||||
interE[i*w+j] = (cur[i*w+j]-interE[i*w+j-1]*Ahor[i*w+j])/denom; |
||||
} |
||||
|
||||
//backward pass:
|
||||
cur[i*w+w-1] = interE[i*w+w-1]; |
||||
for(int j=w-2;j>=0;j--) |
||||
cur[i*w+j] = interE[i*w+j]-interD[i*w+j]*cur[i*w+j+1]; |
||||
} |
||||
} |
||||
|
||||
void WeightedLeastSquaresFilterImpl::verticalPass(double* cur) |
||||
{ |
||||
double denom; |
||||
//forward pass:
|
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
interD[j] = Cvert[j]/Bvert[j]; |
||||
interE[j] = cur[j]/Bvert[j]; |
||||
} |
||||
for(int i=1;i<h;i++) |
||||
{ |
||||
for(int j=0;j<w;j++) |
||||
{ |
||||
denom = Bvert[i*w+j]-interD[(i-1)*w+j]*Avert[i*w+j]; |
||||
interD[i*w+j] = Cvert[i*w+j]/denom; |
||||
interE[i*w+j] = (cur[i*w+j]-interE[(i-1)*w+j]*Avert[i*w+j])/denom; |
||||
} |
||||
} |
||||
//backward pass:
|
||||
for(int j=0;j<w;j++) |
||||
cur[(h-1)*w+j] = interE[(h-1)*w+j]; |
||||
for(int i=h-2;i>=0;i--) |
||||
for(int j=w-1;j>=0;j--) |
||||
cur[i*w+j] = interE[i*w+j]-interD[i*w+j]*cur[(i+1)*w+j]; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CV_EXPORTS_W |
||||
Ptr<WeightedLeastSquaresFilter> createWeightedLeastSquaresFilter(InputArray guide, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
return Ptr<WeightedLeastSquaresFilter>(WeightedLeastSquaresFilterImpl::create(guide, lambda, sigma_color, num_iter)); |
||||
} |
||||
|
||||
CV_EXPORTS_W |
||||
void weightedLeastSquaresFilter(InputArray guide, InputArray src, OutputArray dst, double lambda, double sigma_color, int num_iter) |
||||
{ |
||||
Ptr<WeightedLeastSquaresFilter> wls = createWeightedLeastSquaresFilter(guide, lambda, sigma_color, num_iter); |
||||
wls->filter(src, dst); |
||||
} |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue