-
-
Save kinchungwong/141bfa2d996cb5ae8f42 to your computer and use it in GitHub Desktop.
This is a collection of 6 C++ files that work around the OpenCV bug #1337 issue on x86/x64 architecture.
http://code.opencv.org/issues/1337
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* AffineTransformer.cpp | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#include "stdafx.h" | |
#include "AffineTransformer.h" | |
namespace TiledAffine | |
{ | |
template class AffineTransformer<cv::Point2f, float>; | |
template class AffineTransformer<cv::Point2d, double>; | |
template <class PointType, class ValueType> | |
AffineTransformer<PointType, ValueType>::AffineTransformer() | |
{ | |
memset(m_coefs, 0, sizeof(m_coefs)); | |
} | |
template <class PointType, class ValueType> | |
AffineTransformer<PointType, ValueType>::AffineTransformer(const cv::Mat& matTransform) | |
{ | |
cv::Size sz = matTransform.size(); | |
if (sz.width != 3 || sz.height != 2) | |
throw std::exception(); | |
cv::Mat_<ValueType> matTransform2; | |
matTransform.convertTo(matTransform2, matTransform2.type()); | |
m_coefs[0] = matTransform2(0, 0); | |
m_coefs[1] = matTransform2(0, 1); | |
m_coefs[2] = matTransform2(0, 2); | |
m_coefs[3] = matTransform2(1, 0); | |
m_coefs[4] = matTransform2(1, 1); | |
m_coefs[5] = matTransform2(1, 2); | |
} | |
template <class PointType, class ValueType> | |
PointType AffineTransformer<PointType, ValueType>::operator() (const PointType& in) const | |
{ | |
PointType out; | |
out.x = (PointType::value_type)(m_coefs[0] * in.x + m_coefs[1] * in.y + m_coefs[2]); | |
out.y = (PointType::value_type)(m_coefs[3] * in.x + m_coefs[4] * in.y + m_coefs[5]); | |
return out; | |
} | |
} // TiledAffine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* AffineTransformer.h | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#pragma once | |
namespace TiledAffine | |
{ | |
template < class PointType, class ValueType = PointType::value_type > | |
class AffineTransformer | |
{ | |
public: | |
AffineTransformer(); | |
AffineTransformer(const cv::Mat& matTransform); | |
PointType operator() (const PointType& in) const; | |
private: | |
ValueType m_coefs[6]; | |
}; | |
typedef AffineTransformer<cv::Point2f, float> AffineTransformer2f; | |
typedef AffineTransformer<cv::Point2d, double> AffineTransformer2d; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* TiledAffineProcessor.cpp | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#include "stdafx.h" | |
#include "TiledAffineProcessor.h" | |
namespace TiledAffine | |
{ | |
TiledAffineProcessor::TiledAffineProcessor(const cv::Mat& matSrc, cv::Mat& matDst, const cv::Mat& matTransform, int tileSize) | |
: m_matSrc(matSrc) | |
, m_matDst(matDst) | |
{ | |
if (matSrc.type() != matDst.type()) | |
throw std::exception(); | |
m_interpMode = cv::INTER_LINEAR; | |
m_borderMode = cv::BORDER_TRANSPARENT; | |
m_interpMargin = 3; // depends on interpolation type | |
m_tileSize = tileSize; | |
m_fillColor = cv::Scalar(0); | |
m_srcSize = matSrc.size(); | |
m_dstSize = matDst.size(); | |
m_trans = AffineTransformer2f(matTransform); | |
m_dstParts = TilePartitioner(m_dstSize, m_tileSize); | |
} | |
TiledAffineProcessor::TileIndex TiledAffineProcessor::begin() const | |
{ | |
return 0; | |
} | |
TiledAffineProcessor::TileIndex TiledAffineProcessor::end() const | |
{ | |
return m_dstParts.NumTiles(); | |
} | |
void TiledAffineProcessor::operator() (TileIndex tileId) | |
{ | |
if (tileId < 0 || tileId >= m_dstParts.NumTiles()) | |
return; | |
const std::pair<cv::Range, cv::Range> dstRangeXY = m_dstParts.TileToXyRange(tileId); | |
const std::pair<cv::Range, cv::Range> srcRangeXY = CoalesceIfSourceEmpty(AddSourceInterpMargin(ComputeSourceRange(dstRangeXY))); | |
if (srcRangeXY.first.empty() || srcRangeXY.second.empty()) | |
return; | |
const cv::Range& dstRangeX = dstRangeXY.first; | |
const cv::Range& dstRangeY = dstRangeXY.second; | |
const cv::Range& srcRangeX = srcRangeXY.first; | |
const cv::Range& srcRangeY = srcRangeXY.second; | |
const cv::Mat_<cv::Vec2f> mapXY = ComputeMapping(srcRangeXY, dstRangeXY); | |
const cv::Mat roiSrc = m_matSrc(srcRangeY, srcRangeX).clone(); // note: clone to ensure source matrix width less than 32768 | |
cv::Mat roiDst = m_matDst(dstRangeY, dstRangeX); | |
cv::remap(roiSrc, roiDst, mapXY, cv::noArray(), m_interpMode, m_borderMode, m_fillColor); | |
} | |
std::pair<cv::Range, cv::Range> TiledAffineProcessor::ComputeSourceRange(const std::pair<cv::Range, cv::Range>& dstRangeXY) const | |
{ | |
const cv::Range& dstRangeX = dstRangeXY.first; | |
const cv::Range& dstRangeY = dstRangeXY.second; | |
cv::Point2f dstCorner00 = cv::Point2i(dstRangeX.start, dstRangeY.start); | |
cv::Point2f dstCorner01 = cv::Point2i(dstRangeX.start, dstRangeY.end - 1); | |
cv::Point2f dstCorner10 = cv::Point2i(dstRangeX.end - 1, dstRangeY.start); | |
cv::Point2f dstCorner11 = cv::Point2i(dstRangeX.end - 1, dstRangeY.end - 1); | |
cv::Point2f srcCorner00 = m_trans(dstCorner00); | |
cv::Point2f srcCorner01 = m_trans(dstCorner01); | |
cv::Point2f srcCorner10 = m_trans(dstCorner10); | |
cv::Point2f srcCorner11 = m_trans(dstCorner11); | |
int srcMinX = (int)floor(std::min(std::min(srcCorner00.x, srcCorner01.x), std::min(srcCorner10.x, srcCorner11.x))); | |
int srcMinY = (int)floor(std::min(std::min(srcCorner00.y, srcCorner01.y), std::min(srcCorner10.y, srcCorner11.y))); | |
int srcMaxX = (int)ceil(std::max(std::max(srcCorner00.x, srcCorner01.x), std::max(srcCorner10.x, srcCorner11.x))); | |
int srcMaxY = (int)ceil(std::max(std::max(srcCorner00.y, srcCorner01.y), std::max(srcCorner10.y, srcCorner11.y))); | |
cv::Range srcRangeX(srcMinX, srcMaxX); | |
cv::Range srcRangeY(srcMinY, srcMaxY); | |
return std::make_pair(srcRangeX, srcRangeY); | |
} | |
std::pair<cv::Range, cv::Range> TiledAffineProcessor::AddSourceInterpMargin(const std::pair<cv::Range, cv::Range>& srcRangeXY) const | |
{ | |
const cv::Range& srcRangeX = srcRangeXY.first; | |
const cv::Range& srcRangeY = srcRangeXY.second; | |
int srcMinX = std::max(srcRangeX.start - m_interpMargin, 0); | |
int srcMaxX = std::min(srcRangeX.end + m_interpMargin, m_srcSize.width); | |
int srcMinY = std::max(srcRangeY.start - m_interpMargin, 0); | |
int srcMaxY = std::min(srcRangeY.end + m_interpMargin, m_srcSize.height); | |
return std::make_pair(cv::Range(srcMinX, srcMaxX), cv::Range(srcMinY, srcMaxY)); | |
} | |
std::pair<cv::Range, cv::Range> TiledAffineProcessor::CoalesceIfSourceEmpty(const std::pair<cv::Range, cv::Range>& srcRangeXY) const | |
{ | |
if (srcRangeXY.first.start >= m_srcSize.width || srcRangeXY.second.start >= m_srcSize.height || | |
srcRangeXY.first.end < 0 || srcRangeXY.second.end < 0) | |
{ | |
return std::make_pair(cv::Range(0, 0), cv::Range(0, 0)); | |
} | |
return srcRangeXY; | |
} | |
cv::Mat_<cv::Vec2f> TiledAffineProcessor::ComputeMapping(const RangeXY& srcRangeXY, const RangeXY& dstRangeXY) const | |
{ | |
const cv::Range& dstRangeX = dstRangeXY.first; | |
const cv::Range& dstRangeY = dstRangeXY.second; | |
const cv::Range& srcRangeX = srcRangeXY.first; | |
const cv::Range& srcRangeY = srcRangeXY.second; | |
cv::Mat_<cv::Vec2f> mapXY(cv::Size(dstRangeX.size(), dstRangeY.size())); | |
const cv::Point2f sourceTileOffset = cv::Point2i(srcRangeX.start, srcRangeY.start); | |
for (int dstY = dstRangeY.start; dstY < dstRangeY.end; ++dstY) | |
{ | |
for (int dstX = dstRangeX.start; dstX < dstRangeX.end; ++dstX) | |
{ | |
cv::Point2f dstXY = cv::Point2i(dstX, dstY); | |
cv::Point2f srcXY = m_trans(dstXY) - sourceTileOffset; | |
mapXY(dstY - dstRangeY.start, dstX - dstRangeX.start) = srcXY; | |
} | |
} | |
return mapXY; | |
} | |
} // TiledAffine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* TiledAffineProcessor.h | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#pragma once | |
#include "AffineTransformer.h" | |
#include "TilePartitioner.h" | |
namespace TiledAffine | |
{ | |
/// <summary> | |
/// Processes the affine transform (such as arbitrary rotation) on a large OpenCV image | |
/// by computing the output tiles and copying corresponding sections of input image. | |
/// This is a workaround for OpenCV Bug #1337 (remap fails if input widthstep greater than 32768 bytes) | |
/// http://code.opencv.org/issues/1337 | |
/// </summary> | |
/// | |
class TiledAffineProcessor | |
{ | |
public: | |
typedef int TileIndex; | |
typedef std::pair<cv::Range, cv::Range> RangeXY; | |
public: | |
TiledAffineProcessor(const cv::Mat& matSrc, cv::Mat& matDst, const cv::Mat& matTransform, int tileSize = 1024); | |
TileIndex begin() const; | |
TileIndex end() const; | |
void operator() (TileIndex tileId); | |
private: | |
TiledAffineProcessor(); // not defined | |
TiledAffineProcessor(const TiledAffineProcessor&); // not defined | |
TiledAffineProcessor& operator = (const TiledAffineProcessor&); // not defined | |
private: | |
RangeXY ComputeSourceRange(const RangeXY& dstRangeXY) const; | |
RangeXY AddSourceInterpMargin(const RangeXY& srcRangeXY) const; | |
RangeXY CoalesceIfSourceEmpty(const RangeXY& srcRangeXY) const; | |
cv::Mat_<cv::Vec2f> ComputeMapping(const RangeXY& srcRangeXY, const RangeXY& dstRangeXY) const; | |
private: | |
const cv::Mat m_matSrc; | |
cv::Mat m_matDst; | |
cv::Size m_srcSize; | |
cv::Size m_dstSize; | |
int m_tileSize; | |
int m_interpMode; | |
int m_borderMode; | |
cv::Scalar m_fillColor; | |
// m_interpMargin: size radius of neighboring source pixels that might be used to compute the interpolated value of a single output pixel. | |
int m_interpMargin; | |
TilePartitioner m_dstParts; | |
AffineTransformer2f m_trans; | |
}; | |
} // TiledAffine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* TilePartitioner.cpp | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#include "stdafx.h" | |
#include "TilePartitioner.h" | |
namespace TiledAffine | |
{ | |
TilePartitioner::TilePartitioner() | |
{ | |
m_size = cv::Size(0, 0); | |
m_tileSize = 0; | |
m_numHorz = 0; | |
m_numVert = 0; | |
} | |
TilePartitioner::TilePartitioner(const cv::Size& size, int tileSize) | |
{ | |
m_size = size; | |
m_tileSize = tileSize; | |
m_numHorz = (m_size.width + (m_tileSize - 1)) / m_tileSize; | |
m_numVert = (m_size.height + (m_tileSize - 1)) / m_tileSize; | |
} | |
int TilePartitioner::NumTiles() const | |
{ | |
return m_numHorz * m_numVert; | |
} | |
cv::Range TilePartitioner::AllTiles() const | |
{ | |
return cv::Range(0, m_numHorz * m_numVert); | |
} | |
std::pair<cv::Range, cv::Range> TilePartitioner::TileToXyRange(int tileId) const | |
{ | |
int yTileId = tileId / m_numHorz; | |
int xTileId = tileId % m_numHorz; | |
int yStart = yTileId * m_tileSize; | |
int xStart = xTileId * m_tileSize; | |
int yStop = std::min(yStart + m_tileSize, m_size.height); | |
int xStop = std::min(xStart + m_tileSize, m_size.width); | |
cv::Range xRange(xStart, xStop); | |
cv::Range yRange(yStart, yStop); | |
return std::make_pair(xRange, yRange); | |
} | |
} // TiledAffine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* TilePartitioner.h | |
* Copyright 2013 Compulink Management Center, Inc. | |
*/ | |
#pragma once | |
namespace TiledAffine | |
{ | |
/// <summary>Utility class for iterating through tile partitioning of a 2D image.</summary> | |
/// | |
class TilePartitioner | |
{ | |
public: | |
TilePartitioner(); | |
TilePartitioner(const cv::Size& size, int tileSize); | |
int NumTiles() const; | |
cv::Range AllTiles() const; | |
std::pair<cv::Range, cv::Range> TileToXyRange(int tileId) const; | |
private: | |
cv::Size m_size; | |
int m_tileSize; | |
int m_numHorz; | |
int m_numVert; | |
}; | |
} // TiledAffine |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment