You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

217 lines
9.0 KiB

/*
* SemiGlobalMatcher.h
*
* Copyright (c) 2014-2015 SEACAVE
*
* Author(s):
*
* cDc <cdc.seacave@gmail.com>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Additional Terms:
*
* You are required to preserve legal notices and author attributions in
* that material or in the Appropriate Legal Notices displayed by works
* containing it.
*/
#ifndef _MVS_SEMIGLOBALMATCHER_H_
#define _MVS_SEMIGLOBALMATCHER_H_
// I N C L U D E S /////////////////////////////////////////////////
#include "DepthMap.h"
// D E F I N E S ///////////////////////////////////////////////////
// similarity method
#define SGM_SIMILARITY_WZNCC 1
#define SGM_SIMILARITY_CENSUS 2
#define SGM_SIMILARITY SGM_SIMILARITY_WZNCC
// S T R U C T S ///////////////////////////////////////////////////
namespace MVS {
class Scene;
namespace STEREO {
// An implementation of the popular Semi-Global Matching (SGM) algorithm.
class MVS_API SemiGlobalMatcher
{
public:
typedef uint8_t Mask; // used to mark the valid region to be estimated
typedef int16_t Disparity; // contains the allowable disparity range
typedef uint8_t Cost; // used to describe a single disparity cost
typedef uint16_t AccumCost; // used to accumulate CostType values
typedef uint64_t Index; // index pointing to pixel costs/accumulated-costs
enum : Mask { INVALID = 0, VALID = DECLARE_NO_INDEX(Mask) }; // invalid/valid mask value
enum : Disparity { NO_DISP = DECLARE_NO_INDEX(Disparity) }; // invalid disparity value
enum : AccumCost { NO_ACCUMCOST = DECLARE_NO_INDEX(AccumCost) }; // invalid accumulated cost value
enum : Index { NO_INDEX = DECLARE_NO_INDEX(Index) }; // invalid index value
struct Range {
Disparity minDisp;
Disparity maxDisp;
Disparity avgDisp() const { return (minDisp+maxDisp)>>1; }
Disparity numDisp() const { return maxDisp-minDisp; }
Disparity isValid() const { return minDisp<maxDisp; }
};
struct PixelData {
Index idx; // index to pixel costs/accumulated-costs data
Range range; // first and last disparity evaluated for this pixel
};
typedef TImage<Mask> MaskMap; // image of accumulated disparity cost
typedef TImage<Disparity> DisparityMap; // disparity image type
typedef TImage<AccumCost> AccumCostMap; // image of accumulated disparity cost
typedef CLISTDEF0IDX(PixelData,Index) PixelMap; // map of pixel data
typedef CLISTDEF0IDX(Cost,Index) CostsMap; // map of pre-computed disparity costs
typedef CLISTDEF0IDX(AccumCost,Index) AccumCostsMap; // map of accumulated disparity costs
enum : int { numDirs = 4 }; // 2 or 4 directions accumulated per pixel pass
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
enum : int { halfWindowSizeX = 3, halfWindowSizeY = 4 }; // patch kernel size
#else
enum : int { halfWindowSizeX = 3, halfWindowSizeY = 3 }; // patch kernel size
#endif
enum : int { windowSizeX = halfWindowSizeX*2+1, windowSizeY = halfWindowSizeY*2+1, numTexels = windowSizeX*windowSizeY }; // patch kernel info
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
typedef uint64_t Census; // used to store Census transform
typedef TImage<Census> CensusMap; // image of Census transforms
typedef Image8U ImageGray; // used to store intensities image
STATIC_ASSERT(sizeof(Census)*8 >= numTexels);
#else
typedef WeightedPatchFix<numTexels> WeightedPatch; // pre-computed patch weights
typedef Image32F ImageGray; // used to store normalized float intensities image
#endif
// Available sub-pixel options
enum SgmSubpixelMode {
SUBPIXEL_NA = 0, // no sub-pixel processing
SUBPIXEL_LINEAR,
SUBPIXEL_POLY4,
SUBPIXEL_PARABOLA,
SUBPIXEL_SINE,
SUBPIXEL_COSINE,
SUBPIXEL_LC_BLEND // probably the best option
};
struct ViewData {
Image8U3 imageColor; // color image
ImageGray imageGray; // intensity image
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
CensusMap imageCensus; // image of Census transforms (valid per scale)
#endif
ViewData GetImage(REAL scale) const {
if (ISEQUAL(scale, REAL(1))) {
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
CensusTransform(imageGray, const_cast<CensusMap&>(imageCensus));
#endif
return *this;
}
ASSERT(scale < 1);
ViewData scaledView;
cv::resize(imageColor, scaledView.imageColor, cv::Size(), scale, scale, cv::INTER_AREA);
cv::resize(imageGray, scaledView.imageGray, cv::Size(), scale, scale, cv::INTER_AREA);
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
CensusTransform(scaledView.imageGray, scaledView.imageCensus);
#endif
return scaledView;
}
};
typedef Point2f DepthRange;
typedef TImage<DepthRange> DepthRangeMap;
public:
SemiGlobalMatcher(SgmSubpixelMode subpixelMode=SUBPIXEL_LC_BLEND, Disparity subpixelSteps=4, AccumCost P1=3, AccumCost P2=4, float P2alpha=14, float P2beta=38);
~SemiGlobalMatcher();
void Match(const Scene& scene, IIndex idxImage, IIndex numNeighbors, unsigned minResolution=320);
void Fuse(const Scene& scene, IIndex idxImage, IIndex numNeighbors, unsigned minViews, DepthMap& depthMap, ConfidenceMap& confMap);
static void CreateThreads(unsigned nMaxThreads=1);
static void DestroyThreads();
static void* ThreadWorker(void*);
static void WaitThreadWorkers(unsigned nJobs);
static bool ExportDisparityDataRaw(const String& fileName, const DisparityMap&, const AccumCostMap&, const cv::Size& imageSize, const Matrix3x3& H, const Matrix4x4& Q, Disparity subpixelSteps);
static bool ExportDisparityDataRawFull(const String& fileName, const DisparityMap&, const AccumCostMap&, const cv::Size& imageSize, const Matrix3x3& H, const Matrix4x4& Q, Disparity subpixelSteps);
static bool ImportDisparityDataRaw(const String& fileName, DisparityMap&, AccumCostMap&, cv::Size& imageSize, Matrix3x3& H, Matrix4x4& Q, Disparity& subpixelSteps);
static bool ImportDisparityDataRawFull(const String& fileName, DisparityMap&, AccumCostMap&, cv::Size& imageSize, Matrix3x3& H, Matrix4x4& Q, Disparity& subpixelSteps);
static Image8U3 DisparityMap2Image(const DisparityMap&, Disparity minDisparity=NO_DISP, Disparity maxDisparity=NO_DISP);
static bool ExportDisparityMap(const String& fileName, const DisparityMap&, Disparity minDisparity=NO_DISP, Disparity maxDisparity=NO_DISP);
static bool ExportPointCloud(const String& fileName, const Image&, const DisparityMap&, const Matrix4x4& Q, Disparity subpixelSteps);
static bool ImportPointCloud(const String& fileName, const ImageArr& images, PointCloud&);
protected:
void Match(const ViewData& leftImage, const ViewData& rightImage, DisparityMap& disparityMap, AccumCostMap& costMap);
Index Disparity2RangeMap(const DisparityMap& disparityMap, const MaskMap& maskMap, Disparity minNumDisp=3, Disparity minNumDispInvalid=16);
#if SGM_SIMILARITY == SGM_SIMILARITY_CENSUS
static void CensusTransform(const Image8U& imageGray, CensusMap& imageCensus);
#endif
static void ConsistencyCrossCheck(DisparityMap& l2r, const DisparityMap& r2l, Disparity thCross=1);
static void FilterByCost(DisparityMap&, const AccumCostMap&, AccumCost th);
static void ExtractMask(const DisparityMap&, MaskMap&, int thValid=3);
static void FlipDirection(const DisparityMap& l2r, DisparityMap& r2l);
static void UpscaleMask(MaskMap& maskMap, const cv::Size& size2x);
void RefineDisparityMap(DisparityMap& disparityMap) const;
#ifndef _RELEASE
void DisplayState(const cv::Size& size) const;
#endif
static CLISTDEF0IDX(AccumCost,int) GenerateP2s(AccumCost P2, float P2alpha, float P2beta);
static void Depth2DisparityMap(const DepthMap&, const Matrix3x3& invH, const Matrix4x4& invQ, Disparity subpixelSteps, DisparityMap&);
static void Disparity2DepthMap(const DisparityMap&, const AccumCostMap&, const Matrix3x3& H, const Matrix4x4& Q, Disparity subpixelSteps, DepthMap&, ConfidenceMap&);
static bool ProjectDisparity2DepthMap(const DisparityMap&, const AccumCostMap&, const Matrix4x4& Q, Disparity subpixelSteps, DepthMap&, DepthRangeMap&, ConfidenceMap&);
protected:
// parameters
SgmSubpixelMode subpixelMode;
Disparity subpixelSteps;
AccumCost P1;
CLISTDEF0IDX(AccumCost,int) P2s;
// main memory buffers that must be allocated
PixelMap imagePixels;
CostsMap imageCosts;
AccumCostsMap imageAccumCosts;
Disparity maxNumDisp; // maximum number of disparities per-pixel
// multi-threading
static EventThreadPool threads; // worker threads
static Semaphore sem; // signal job end
};
/*----------------------------------------------------------------*/
MVS_API bool ExportCamerasEngin(const Scene&, const String& fileName);
/*----------------------------------------------------------------*/
} // namespace STEREO
} // namespace MVS
#endif // _MVS_SEMIGLOBALMATCHER_H_