Commit e15eabe3 authored by Fedor Morozov's avatar Fedor Morozov

Ghostbusters

parent 833f8d16
...@@ -164,7 +164,7 @@ createTonemapMantiuk(float gamma = 1.0f, float scale = 0.7f, float saturation = ...@@ -164,7 +164,7 @@ createTonemapMantiuk(float gamma = 1.0f, float scale = 0.7f, float saturation =
class CV_EXPORTS_W ExposureAlign : public Algorithm class CV_EXPORTS_W ExposureAlign : public Algorithm
{ {
public: public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArrayOfArrays dst, CV_WRAP virtual void process(InputArrayOfArrays src, std::vector<Mat>& dst,
const std::vector<float>& times, InputArray response) = 0; const std::vector<float>& times, InputArray response) = 0;
}; };
...@@ -173,22 +173,26 @@ public: ...@@ -173,22 +173,26 @@ public:
class CV_EXPORTS_W AlignMTB : public ExposureAlign class CV_EXPORTS_W AlignMTB : public ExposureAlign
{ {
public: public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArrayOfArrays dst, CV_WRAP virtual void process(InputArrayOfArrays src, std::vector<Mat>& dst,
const std::vector<float>& times, InputArray response) = 0; const std::vector<float>& times, InputArray response) = 0;
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArrayOfArrays dst) = 0; CV_WRAP virtual void process(InputArrayOfArrays src, std::vector<Mat>& dst) = 0;
CV_WRAP virtual void calculateShift(InputArray img0, InputArray img1, Point& shift) = 0; CV_WRAP virtual void calculateShift(InputArray img0, InputArray img1, Point& shift) = 0;
CV_WRAP virtual void shiftMat(InputArray src, OutputArray dst, const Point shift) = 0; CV_WRAP virtual void shiftMat(InputArray src, OutputArray dst, const Point shift) = 0;
CV_WRAP virtual void computeBitmaps(Mat& img, Mat& tb, Mat& eb) = 0;
CV_WRAP virtual int getMaxBits() const = 0; CV_WRAP virtual int getMaxBits() const = 0;
CV_WRAP virtual void setMaxBits(int max_bits) = 0; CV_WRAP virtual void setMaxBits(int max_bits) = 0;
CV_WRAP virtual int getExcludeRange() const = 0; CV_WRAP virtual int getExcludeRange() const = 0;
CV_WRAP virtual void setExcludeRange(int exclude_range) = 0; CV_WRAP virtual void setExcludeRange(int exclude_range) = 0;
CV_WRAP virtual bool getCut() const = 0;
CV_WRAP virtual void setCut(bool value) = 0;
}; };
CV_EXPORTS_W Ptr<AlignMTB> createAlignMTB(int max_bits = 6, int exclude_range = 4); CV_EXPORTS_W Ptr<AlignMTB> createAlignMTB(int max_bits = 6, int exclude_range = 4, bool cut = true);
class CV_EXPORTS_W ExposureCalibrate : public Algorithm class CV_EXPORTS_W ExposureCalibrate : public Algorithm
{ {
...@@ -206,9 +210,6 @@ public: ...@@ -206,9 +210,6 @@ public:
CV_WRAP virtual int getSamples() const = 0; CV_WRAP virtual int getSamples() const = 0;
CV_WRAP virtual void setSamples(int samples) = 0; CV_WRAP virtual void setSamples(int samples) = 0;
CV_WRAP virtual bool getTest() const = 0;
CV_WRAP virtual void setTest(bool val) = 0;
}; };
CV_EXPORTS_W Ptr<CalibrateDebevec> createCalibrateDebevec(int samples = 50, float lambda = 10.0f); CV_EXPORTS_W Ptr<CalibrateDebevec> createCalibrateDebevec(int samples = 50, float lambda = 10.0f);
...@@ -278,6 +279,65 @@ public: ...@@ -278,6 +279,65 @@ public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, const std::vector<float>& times) = 0; CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, const std::vector<float>& times) = 0;
}; };
CV_EXPORTS_W Ptr<MergeRobertson> createMergeRobertson();
class CV_EXPORTS_W Ghostbuster : public Algorithm
{
public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) = 0;
};
// "Ghost Detection and Removal in High Dynamic Range Images", Sidibe et al., 2009
class CV_EXPORTS_W GhostbusterOrder : public Ghostbuster
{
public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) = 0;
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst) = 0;
CV_WRAP virtual int getUnderexp() = 0;
CV_WRAP virtual void setUnderexp(int value) = 0;
CV_WRAP virtual int getOverexp() = 0;
CV_WRAP virtual void setOverexp(int value) = 0;
};
CV_EXPORTS_W Ptr<GhostbusterOrder> createGhostbusterOrder(int underexp = 20, int overexp = 240);
// "Fast and Robust High Dynamic Range Image Generation with Camera and Object Movement", Grosch, 2006
class CV_EXPORTS_W GhostbusterPredict : public Ghostbuster
{
public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) = 0;
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times) = 0;
CV_WRAP virtual int getThreshold() = 0;
CV_WRAP virtual void setThreshold(int value) = 0;
CV_WRAP virtual int getUnderexp() = 0;
CV_WRAP virtual void setUnderexp(int value) = 0;
CV_WRAP virtual int getOverexp() = 0;
CV_WRAP virtual void setOverexp(int value) = 0;
};
CV_EXPORTS_W Ptr<GhostbusterPredict> createGhostbusterPredict(int thresh = 10, int underexp = 20, int overexp = 240);
// "Bitmap Movement Detection: HDR for Dynamic Scenes", Pece, Kautz, 2010
class CV_EXPORTS_W GhostbusterBitmap : public Ghostbuster
{
public:
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) = 0;
CV_WRAP virtual void process(InputArrayOfArrays src, OutputArray dst) = 0;
CV_WRAP virtual int getExclude() = 0;
CV_WRAP virtual void setExclude(int value) = 0;
};
CV_EXPORTS_W Ptr<GhostbusterBitmap> createGhostbusterBitmap(int exclude = 4);
} // cv } // cv
#endif #endif
This diff is collapsed.
...@@ -55,8 +55,7 @@ public: ...@@ -55,8 +55,7 @@ public:
samples(samples), samples(samples),
lambda(lambda), lambda(lambda),
name("CalibrateDebevec"), name("CalibrateDebevec"),
w(tringleWeights()), w(tringleWeights())
test(false)
{ {
} }
...@@ -84,9 +83,6 @@ public: ...@@ -84,9 +83,6 @@ public:
for(int i = 0; i < samples; i++) { for(int i = 0; i < samples; i++) {
int pos = 3 * (rand() % images[0].total()) + channel; int pos = 3 * (rand() % images[0].total()) + channel;
if(test) {
pos = 3 * i + channel;
}
for(size_t j = 0; j < images.size(); j++) { for(size_t j = 0; j < images.size(); j++) {
int val = (images[j].ptr() + pos)[0]; int val = (images[j].ptr() + pos)[0];
...@@ -113,9 +109,6 @@ public: ...@@ -113,9 +109,6 @@ public:
exp(result, result); exp(result, result);
} }
bool getTest() const { return test; }
void setTest(bool val) { test = val; }
int getSamples() const { return samples; } int getSamples() const { return samples; }
void setSamples(int val) { samples = val; } void setSamples(int val) { samples = val; }
...@@ -141,7 +134,6 @@ protected: ...@@ -141,7 +134,6 @@ protected:
String name; String name;
int samples; int samples;
float lambda; float lambda;
bool test;
Mat w; Mat w;
}; };
......
...@@ -92,4 +92,21 @@ void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation) ...@@ -92,4 +92,21 @@ void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation)
merge(channels, dst); merge(channels, dst);
} }
Mat linearResponse(int channels)
{
Mat single_response = Mat(256, 1, CV_32F);
for(int i = 1; i < 256; i++) {
single_response.at<float>(i) = static_cast<float>(i);
}
single_response.at<float>(0) = static_cast<float>(1);
std::vector<Mat> splitted(channels);
for(int c = 0; c < channels; c++) {
splitted[c] = single_response;
}
Mat result;
merge(splitted, result);
return result;
}
}; };
...@@ -56,6 +56,7 @@ void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation); ...@@ -56,6 +56,7 @@ void mapLuminance(Mat src, Mat dst, Mat lum, Mat new_lum, float saturation);
Mat RobertsonWeights(); Mat RobertsonWeights();
Mat linearResponse(int channels);
}; };
#endif #endif
...@@ -125,23 +125,6 @@ public: ...@@ -125,23 +125,6 @@ public:
protected: protected:
String name; String name;
Mat weights; Mat weights;
Mat linearResponse(int channels)
{
Mat single_response = Mat(256, 1, CV_32F);
for(int i = 1; i < 256; i++) {
single_response.at<float>(i) = static_cast<float>(i);
}
single_response.at<float>(0) = static_cast<float>(1);
std::vector<Mat> splitted(channels);
for(int c = 0; c < channels; c++) {
splitted[c] = single_response;
}
Mat result;
merge(splitted, result);
return result;
}
}; };
Ptr<MergeDebevec> createMergeDebevec() Ptr<MergeDebevec> createMergeDebevec()
...@@ -329,7 +312,7 @@ public: ...@@ -329,7 +312,7 @@ public:
Mat response = input_response.getMat(); Mat response = input_response.getMat();
if(response.empty()) { if(response.empty()) {
response = linearResponse(channels); response = linearResponse(channels) / 128.0f;
} }
CV_Assert(response.rows == 256 && response.cols == 1 && CV_Assert(response.rows == 256 && response.cols == 1 &&
response.channels() == channels); response.channels() == channels);
...@@ -355,17 +338,6 @@ public: ...@@ -355,17 +338,6 @@ public:
protected: protected:
String name; String name;
Mat weight; Mat weight;
Mat linearResponse(int channels)
{
Mat response = Mat::zeros(256, 1, CV_32FC3);
for(int i = 0; i < 256; i++) {
for(int c = 0; c < 3; c++) {
response.at<Vec3f>(i)[c] = static_cast<float>(i) / 128.0f;
}
}
return response;
}
}; };
Ptr<MergeRobertson> createMergeRobertson() Ptr<MergeRobertson> createMergeRobertson()
......
...@@ -79,11 +79,11 @@ void loadExposureSeq(String path, vector<Mat>& images, vector<float>& times = DE ...@@ -79,11 +79,11 @@ void loadExposureSeq(String path, vector<Mat>& images, vector<float>& times = DE
void loadResponseCSV(String path, Mat& response) void loadResponseCSV(String path, Mat& response)
{ {
response = Mat(256, 1, CV_32FC3); response = Mat(256, 1, CV_32FC3);
ifstream resp_file(path.c_str()); ifstream resp_file(path);
for(int i = 0; i < 256; i++) { for(int i = 0; i < 256; i++) {
for(int c = 0; c < 3; c++) { for(int c = 0; c < 3; c++) {
resp_file >> response.at<Vec3f>(i)[c]; resp_file >> response.at<Vec3f>(i)[c];
resp_file.ignore(1); resp_file.ignore(1);
} }
} }
resp_file.close(); resp_file.close();
...@@ -101,31 +101,31 @@ TEST(Photo_Tonemap, regression) ...@@ -101,31 +101,31 @@ TEST(Photo_Tonemap, regression)
linear->process(img, result); linear->process(img, result);
loadImage(test_path + "linear.png", expected); loadImage(test_path + "linear.png", expected);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 0); checkEqual(result, expected, 3);
Ptr<TonemapDrago> drago = createTonemapDrago(gamma); Ptr<TonemapDrago> drago = createTonemapDrago(gamma);
drago->process(img, result); drago->process(img, result);
loadImage(test_path + "drago.png", expected); loadImage(test_path + "drago.png", expected);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 0); checkEqual(result, expected, 3);
Ptr<TonemapDurand> durand = createTonemapDurand(gamma); Ptr<TonemapDurand> durand = createTonemapDurand(gamma);
durand->process(img, result); durand->process(img, result);
loadImage(test_path + "durand.png", expected); loadImage(test_path + "durand.png", expected);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 0); checkEqual(result, expected, 3);
Ptr<TonemapReinhardDevlin> reinhard_devlin = createTonemapReinhardDevlin(gamma); Ptr<TonemapReinhardDevlin> reinhard_devlin = createTonemapReinhardDevlin(gamma);
reinhard_devlin->process(img, result); reinhard_devlin->process(img, result);
loadImage(test_path + "reinharddevlin.png", expected); loadImage(test_path + "reinharddevlin.png", expected);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 0); checkEqual(result, expected, 3);
Ptr<TonemapMantiuk> mantiuk = createTonemapMantiuk(gamma); Ptr<TonemapMantiuk> mantiuk = createTonemapMantiuk(gamma);
mantiuk->process(img, result); mantiuk->process(img, result);
loadImage(test_path + "mantiuk.png", expected); loadImage(test_path + "mantiuk.png", expected);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(result, expected, 0); checkEqual(result, expected, 3);
} }
TEST(Photo_AlignMTB, regression) TEST(Photo_AlignMTB, regression)
...@@ -169,7 +169,7 @@ TEST(Photo_MergeMertens, regression) ...@@ -169,7 +169,7 @@ TEST(Photo_MergeMertens, regression)
loadImage(test_path + "merge/mertens.png", expected); loadImage(test_path + "merge/mertens.png", expected);
merge->process(images, result); merge->process(images, result);
result.convertTo(result, CV_8UC3, 255); result.convertTo(result, CV_8UC3, 255);
checkEqual(expected, result, 0); checkEqual(expected, result, 3);
} }
TEST(Photo_MergeDebevec, regression) TEST(Photo_MergeDebevec, regression)
...@@ -188,7 +188,7 @@ TEST(Photo_MergeDebevec, regression) ...@@ -188,7 +188,7 @@ TEST(Photo_MergeDebevec, regression)
loadImage(test_path + "merge/debevec.exr", expected); loadImage(test_path + "merge/debevec.exr", expected);
merge->process(images, result, times, response); merge->process(images, result, times, response);
imwrite("test.exr", result); imwrite("test.exr", result);
checkEqual(expected, result, 1e-3f); checkEqual(expected, result, 1e-2f);
} }
TEST(Photo_CalibrateDebevec, regression) TEST(Photo_CalibrateDebevec, regression)
...@@ -197,11 +197,11 @@ TEST(Photo_CalibrateDebevec, regression) ...@@ -197,11 +197,11 @@ TEST(Photo_CalibrateDebevec, regression)
vector<Mat> images; vector<Mat> images;
vector<float> times; vector<float> times;
Mat expected, response; Mat response, expected;
loadExposureSeq(test_path + "exposures/", images, times); loadExposureSeq(test_path + "exposures/", images, times);
loadResponseCSV(test_path + "calibrate/debevec.csv", expected); loadResponseCSV(test_path + "calibrate/debevec.csv", expected);
Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec(); Ptr<CalibrateDebevec> calibrate = createCalibrateDebevec();
calibrate->setTest(true); srand(1);
calibrate->process(images, response, times); calibrate->process(images, response, times);
checkEqual(expected, response, 1e-3f); checkEqual(expected, response, 1e-3f);
} }
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