|
|
|
@ -263,284 +263,5 @@ Ptr<AlignMTB> createAlignMTB(int max_bits, int exclude_range, bool cut) |
|
|
|
|
return new AlignMTBImpl(max_bits, exclude_range, cut); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class floatIndexCmp { |
|
|
|
|
public: |
|
|
|
|
floatIndexCmp(std::vector<float> data) : |
|
|
|
|
data(data) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool operator() (int i,int j)
|
|
|
|
|
{
|
|
|
|
|
return data[i] < data[j]; |
|
|
|
|
} |
|
|
|
|
protected: |
|
|
|
|
std::vector<float> data; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class GhostbusterOrderImpl : public GhostbusterOrder |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
GhostbusterOrderImpl(int underexp, int overexp) : |
|
|
|
|
underexp(underexp), |
|
|
|
|
overexp(overexp), |
|
|
|
|
name("GhostbusterOrder") |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response)
|
|
|
|
|
{ |
|
|
|
|
process(src, dst); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void process(InputArrayOfArrays src, OutputArray dst) |
|
|
|
|
{ |
|
|
|
|
std::vector<Mat> unsorted_images; |
|
|
|
|
src.getMatVector(unsorted_images); |
|
|
|
|
checkImageDimensions(unsorted_images); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> images; |
|
|
|
|
sortImages(unsorted_images, images); |
|
|
|
|
|
|
|
|
|
int channels = images[0].channels(); |
|
|
|
|
dst.create(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
Mat res = Mat::zeros(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
std::vector<Mat> splitted(channels); |
|
|
|
|
split(images[0], splitted); |
|
|
|
|
for(size_t i = 0; i < images.size() - 1; i++) { |
|
|
|
|
|
|
|
|
|
std::vector<Mat> next_splitted(channels); |
|
|
|
|
split(images[i + 1], next_splitted); |
|
|
|
|
|
|
|
|
|
for(int c = 0; c < channels; c++) { |
|
|
|
|
Mat exposed = (splitted[c] >= underexp) & (splitted[c] <= overexp); |
|
|
|
|
exposed &= (next_splitted[c] >= underexp) & (next_splitted[c] <= overexp); |
|
|
|
|
Mat ghost = (splitted[c] > next_splitted[c]) & exposed; |
|
|
|
|
res |= ghost; |
|
|
|
|
} |
|
|
|
|
splitted = next_splitted; |
|
|
|
|
} |
|
|
|
|
res.copyTo(dst.getMat()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int getUnderexp() {return underexp;} |
|
|
|
|
void setUnderexp(int value) {underexp = value;} |
|
|
|
|
|
|
|
|
|
int getOverexp() {return overexp;} |
|
|
|
|
void setOverexp(int value) {overexp = value;} |
|
|
|
|
|
|
|
|
|
void write(FileStorage& fs) const |
|
|
|
|
{ |
|
|
|
|
fs << "name" << name |
|
|
|
|
<< "overexp" << overexp |
|
|
|
|
<< "underexp" << underexp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void read(const FileNode& fn) |
|
|
|
|
{ |
|
|
|
|
FileNode n = fn["name"]; |
|
|
|
|
CV_Assert(n.isString() && String(n) == name); |
|
|
|
|
overexp = fn["overexp"]; |
|
|
|
|
underexp = fn["underexp"]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
int overexp, underexp; |
|
|
|
|
String name; |
|
|
|
|
|
|
|
|
|
void sortImages(std::vector<Mat>& images, std::vector<Mat>& sorted) |
|
|
|
|
{ |
|
|
|
|
std::vector<int>indices(images.size()); |
|
|
|
|
std::vector<float>means(images.size()); |
|
|
|
|
for(size_t i = 0; i < images.size(); i++) { |
|
|
|
|
indices[i] = i; |
|
|
|
|
means[i] = mean(mean(images[i]))[0]; |
|
|
|
|
} |
|
|
|
|
sort(indices.begin(), indices.end(), floatIndexCmp(means)); |
|
|
|
|
sorted.resize(images.size()); |
|
|
|
|
for(size_t i = 0; i < images.size(); i++) { |
|
|
|
|
sorted[i] = images[indices[i]]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Ptr<GhostbusterOrder> createGhostbusterOrder(int underexp, int overexp) |
|
|
|
|
{ |
|
|
|
|
return new GhostbusterOrderImpl(underexp, overexp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class GhostbusterPredictImpl : public GhostbusterPredict |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
GhostbusterPredictImpl(int thresh, int underexp, int overexp) : |
|
|
|
|
thresh(thresh), |
|
|
|
|
underexp(underexp), |
|
|
|
|
overexp(overexp), |
|
|
|
|
name("GhostbusterPredict") |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) |
|
|
|
|
{ |
|
|
|
|
std::vector<Mat> images; |
|
|
|
|
src.getMatVector(images); |
|
|
|
|
checkImageDimensions(images); |
|
|
|
|
|
|
|
|
|
int channels = images[0].channels(); |
|
|
|
|
dst.create(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
Mat res = Mat::zeros(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
Mat radiance; |
|
|
|
|
LUT(images[0], response, radiance); |
|
|
|
|
std::vector<Mat> splitted(channels); |
|
|
|
|
split(radiance, splitted); |
|
|
|
|
std::vector<Mat> resp_split(channels); |
|
|
|
|
split(response, resp_split); |
|
|
|
|
for(size_t i = 0; i < images.size() - 1; i++) { |
|
|
|
|
|
|
|
|
|
std::vector<Mat> next_splitted(channels); |
|
|
|
|
LUT(images[i + 1], response, radiance); |
|
|
|
|
split(radiance, next_splitted); |
|
|
|
|
|
|
|
|
|
for(int c = 0; c < channels; c++) { |
|
|
|
|
|
|
|
|
|
Mat predicted = splitted[c] / times[i] * times[i + 1]; |
|
|
|
|
|
|
|
|
|
Mat low = max(thresh, next_splitted[c]) - thresh; |
|
|
|
|
Mat high = min(255 - thresh, next_splitted[c]) + thresh; |
|
|
|
|
low.convertTo(low, CV_8U); |
|
|
|
|
high.convertTo(high, CV_8U); |
|
|
|
|
LUT(low, resp_split[c], low); |
|
|
|
|
LUT(high, resp_split[c], high); |
|
|
|
|
|
|
|
|
|
Mat exposed = (splitted[c] >= underexp) & (splitted[c] <= overexp); |
|
|
|
|
exposed &= (next_splitted[c] >= underexp) & (next_splitted[c] <= overexp); |
|
|
|
|
|
|
|
|
|
Mat ghost = (low < predicted) & (predicted < high); |
|
|
|
|
ghost &= exposed; |
|
|
|
|
res |= ghost; |
|
|
|
|
} |
|
|
|
|
splitted = next_splitted; |
|
|
|
|
} |
|
|
|
|
res.copyTo(dst.getMat()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times) |
|
|
|
|
{ |
|
|
|
|
Mat response = linearResponse(3); |
|
|
|
|
response.at<Vec3f>(0) = response.at<Vec3f>(1); |
|
|
|
|
process(src, dst, times, response); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
CV_WRAP virtual int getThreshold() {return thresh;} |
|
|
|
|
CV_WRAP virtual void setThreshold(int value) {thresh = value;} |
|
|
|
|
|
|
|
|
|
int getUnderexp() {return underexp;} |
|
|
|
|
void setUnderexp(int value) {underexp = value;} |
|
|
|
|
|
|
|
|
|
int getOverexp() {return overexp;} |
|
|
|
|
void setOverexp(int value) {overexp = value;} |
|
|
|
|
|
|
|
|
|
void write(FileStorage& fs) const |
|
|
|
|
{ |
|
|
|
|
fs << "name" << name |
|
|
|
|
<< "overexp" << overexp |
|
|
|
|
<< "underexp" << underexp |
|
|
|
|
<< "thresh" << thresh; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void read(const FileNode& fn) |
|
|
|
|
{ |
|
|
|
|
FileNode n = fn["name"]; |
|
|
|
|
CV_Assert(n.isString() && String(n) == name); |
|
|
|
|
overexp = fn["overexp"]; |
|
|
|
|
underexp = fn["underexp"]; |
|
|
|
|
thresh = fn["thresh"]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
int thresh, underexp, overexp; |
|
|
|
|
String name; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Ptr<GhostbusterPredict> createGhostbusterPredict(int thresh, int underexp, int overexp) |
|
|
|
|
{ |
|
|
|
|
return new GhostbusterPredictImpl(thresh, underexp, overexp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class GhostbusterBitmapImpl : public GhostbusterBitmap |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
GhostbusterBitmapImpl(int exclude) : |
|
|
|
|
exclude(exclude), |
|
|
|
|
name("GhostbusterBitmap") |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void process(InputArrayOfArrays src, OutputArray dst, std::vector<float>& times, Mat response) |
|
|
|
|
{ |
|
|
|
|
process(src, dst); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void process(InputArrayOfArrays src, OutputArray dst) |
|
|
|
|
{ |
|
|
|
|
std::vector<Mat> images; |
|
|
|
|
src.getMatVector(images); |
|
|
|
|
checkImageDimensions(images); |
|
|
|
|
|
|
|
|
|
int channels = images[0].channels(); |
|
|
|
|
dst.create(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
Mat res = Mat::zeros(images[0].size(), CV_8U); |
|
|
|
|
|
|
|
|
|
Ptr<AlignMTB> MTB = createAlignMTB(); |
|
|
|
|
MTB->setExcludeRange(exclude); |
|
|
|
|
|
|
|
|
|
for(size_t i = 0; i < images.size(); i++) { |
|
|
|
|
Mat gray; |
|
|
|
|
if(channels == 1) { |
|
|
|
|
gray = images[i]; |
|
|
|
|
} else { |
|
|
|
|
cvtColor(images[i], gray, COLOR_RGB2GRAY); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Mat tb, eb; |
|
|
|
|
MTB->computeBitmaps(gray, tb, eb); |
|
|
|
|
tb &= eb & 1; |
|
|
|
|
res += tb;
|
|
|
|
|
} |
|
|
|
|
res = (res > 0) & (res < images.size()); |
|
|
|
|
res.copyTo(dst.getMat()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int getExclude() {return exclude;} |
|
|
|
|
void setExclude(int value) {exclude = value;} |
|
|
|
|
|
|
|
|
|
void write(FileStorage& fs) const |
|
|
|
|
{ |
|
|
|
|
fs << "name" << name |
|
|
|
|
<< "exclude" << exclude; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void read(const FileNode& fn) |
|
|
|
|
{ |
|
|
|
|
FileNode n = fn["name"]; |
|
|
|
|
CV_Assert(n.isString() && String(n) == name); |
|
|
|
|
exclude = fn["exclude"]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
int exclude; |
|
|
|
|
String name; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Ptr<GhostbusterBitmap> createGhostbusterBitmap(int exclude) |
|
|
|
|
{ |
|
|
|
|
return new GhostbusterBitmapImpl(exclude); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|