假设我有以下两个图像A和B。
请注意,对于n像素行(由两个红色矩形表示),A的底部与B的顶部重叠。A和B的列数相同,但行数 可能 不同。
n
两个问题:
如果任何人都可以使用任何一种语言(首选C / C ++,C#,Java和JavaScript)指向一种算法或更好的一种实现,则将不胜感激。
FFT解决方案可能比您期望的要复杂。对于一般问题,这可能是唯一可靠的方法。
对于简单的解决方案,您需要开始进行假设。例如,您能否保证图像的列对齐(除非注明的更改)?这使您可以走@nm建议的路径
您是否可以将图像切成垂直条纹,并且如果有足够比例的条纹匹配,可以考虑将行匹配吗?
[如果需要对此进行鲁棒处理,可以重做以使用带有差异列偏移量的几次传递。]
这给出了如下内容:
class Image { public: virtual ~Image() {} typedef int Pixel; virtual Pixel* getRow(int rowId) const = 0; virtual int getWidth() const = 0; virtual int getHeight() const = 0; }; class Analyser { Analyser(const Image& a, const Image& b) : a_(a), b_(b) {} typedef Image::Pixel* Section; static const int numStrips = 16; struct StripId { StripId(int r = 0, int c = 0) : row_(r), strip_(c) {} int row_; int strip_; }; typedef std::unordered_map<unsigned, StripId> StripTable; int numberOfOverlappingRows() { int commonWidth = std::min(a_.getWidth(), b_.getWidth()); int stripWidth = commonWidth/numStrips; StripTable aHash; createStripTable(aHash, a_, stripWidth); StripTable bHash; createStripTable(bHash, b_, stripWidth); // This is the position that the bottom row of A appears in B. int bottomOfA = 0; bool canFindBottomOfAInB = canFindLine(a_.getRow(a_.getHeight() - 1), bHash, stripWidth, bottomOfA); int topOfB= 0; bool canFindTopOfBInA = canFindLine(b_.getRow(0), aHash, stripWidth, topOfB); int topOFBfromBottomOfA = a_.getHeight() - topOfB; // Expect topOFBfromBottomOfA == bottomOfA return bottomOfA; } bool canFindLine(Image::Pixel* source, StripTable& target, int stripWidth, int& matchingRow) { Image::Pixel* strip = source; std::map<int, int> matchedRows; for(int index = 0; index < stripWidth; ++index) { Image::Pixel hashValue = getHashOfStrip(strip,stripWidth); bool match = target.count(hashValue) > 0; if (match) { ++matchedRows[target[hashValue].row_]; } strip += stripWidth; } // Can set a threshold requiring more matches than 0 if (matchedRows.size() == 0) return false; // FIXME return the most matched row. matchingRow = matchedRows.begin()->first; return true; } Image::Pixel* getStrip(const Image& im, int row, int stripId, int stripWidth) { return im.getRow(row) + stripId * stripWidth; } static Image::Pixel getHashOfStrip(Image::Pixel* strip, unsigned width) { Image::Pixel hashValue = 0; for(unsigned col = 0; col < width; ++col) { hashValue |= *(strip + col); } } void createStripTable(StripTable& hash, const Image& image, int stripWidth) { for(int row = 0; row < image.getHeight(); ++row) { for(int index = 0; index < stripWidth; ++index) { // Warning: Not this simple! // If images are sourced from lossy intermediate and hence pixels not _exactly_ the same, need some kind of fuzzy equality here. // Details are going to depend on the image format etc, but this is the gist. Image::Pixel* strip = getStrip(image, row, index, stripWidth); Image::Pixel hashValue = getHashOfStrip(strip,stripWidth); hash[hashValue] = StripId(row, index); } } } const Image& a_; const Image& b_; };