searchborder.hh
来自「Motion JPEG编解码器源代码」· HH 代码 · 共 2,118 行 · 第 1/5 页
HH
2,118 行
#ifndef __SEARCH_BORDER_H__#define __SEARCH_BORDER_H__// This file (C) 2004 Steven Boswell. All rights reserved.// Released to the public under the GNU General Public License.// See the file COPYING for more information.#include "config.h"#include <assert.h>#include "mjpeg_types.h"#include "TemplateLib.hh"#include "Limits.hh"#include "DoublyLinkedList.hh"#include "SetRegion2D.hh"// HACK: for development error messages.#include <stdio.h>// Define this to print region unions/subtractions.#ifdef DEBUG_REGION2D// #define PRINTREGIONMATH#endif // DEBUG_REGION2D// Define this to print details of the search-border's progress.#ifdef DEBUG_REGION2D// #define PRINT_SEARCHBORDER#endif // DEBUG_REGION2D// The generic search-border class. It's parameterized by the numeric// type to use for pixel indices and a numeric type big enough to hold// the product of the largest expected frame width/height.// When constructed, it's configured with the size of the frame in which// it operates, and the width/height of pixel groups to operate on.//// The search border keeps track of all regions on the border between// the searched area and the not-yet-searched area. It also constructs// regions so that each one is contiguous, and not contiguous with any// other region. When no new pixel-group could possibly intersect a// region, that region is removed from the border and handed back to// the client.//// The meaning of the regions it keeps track of is abstract. The// original purpose was to help the motion-searcher keep track of moved// regions, i.e. pixels in the new frame that match pixels in the// reference frame, only moved. But it could presumably be used for// other purposes, e.g. if it assembled regions of pixels that had// exactly one frame reference, it could be used to detect bit noise,// film lint/scratches, or even LaserDisc rot.//// As the search-border proceeds through the frame, it maintains a list// of all regions that intersect with the current pixel-group. That// way, when it comes time to add a new match, all regions that// intersect it are already known.template <class PIXELINDEX, class FRAMESIZE>class SearchBorder{public: typedef SetRegion2D<PIXELINDEX,FRAMESIZE> Region_t; // How we use Region2D<>. class MovedRegion; // A moved region of pixels that has been detected. // Derived from Region_t; defined below. SearchBorder(); // Default constructor. virtual ~SearchBorder(); // Destructor. void Init (Status_t &a_reStatus, PIXELINDEX a_tnWidth, PIXELINDEX a_tnHeight, PIXELINDEX a_tnPGW, PIXELINDEX a_tnPGH); // Initializer. Provide the dimension of the frame and the // dimension of pixel-groups. void StartFrame (Status_t &a_reStatus); // Initialize the search-border, i.e. start in the upper-left // corner. void MoveRight (Status_t &a_reStatus); // Move one pixel to the right, adding and removing regions from // the potentially-intersecting list. void MoveLeft (Status_t &a_reStatus); // Move one pixel to the left, adding and removing regions from // the potentially-intersecting list. void MoveDown (Status_t &a_reStatus); // Move down a line. Find all regions that can no longer // be contiguous with new matches, and hand them back to the // client. Then rotate the border structures, making the // least-recent current border into the last border, etc. inline FRAMESIZE NumberOfActiveRegions (void) const; // Return the number of regions that would intersect with the // current pixel-group. FRAMESIZE AddNewMatch (Status_t &a_reStatus, PIXELINDEX a_tnMotionX, PIXELINDEX a_tnMotionY); // Accept a new match for a pixel-group, with the given // motion-vector. May cause regions under construction to get // merged together. // Returns the size of the region containing the current // pixel-group. MovedRegion *ChooseBestActiveRegion (Status_t &a_reStatus); // Remove all regions that matched the current pixel-group, // except for the best one, and return it. void FinishFrame (Status_t &a_reStatus); // Clean up the search border at the end of a frame, e.g. hand // all remaining regions back to the client. virtual void OnCompletedRegion (Status_t &a_reStatus, MovedRegion *a_pRegion) = 0; // Hand a completed region to our client. Subclasses must // override this to describe how to do this. // A moved region of pixels that has been detected. // All extents are in the coordinate system of the new frame; that // makes it easy to unify/subtract regions without regard to their // motion vector. class MovedRegion : public Region_t { private: typedef Region_t BaseClass; // Keep track of who our base class is. public: MovedRegion (typename BaseClass::Allocator &a_rAlloc = BaseClass::Extents::Imp::sm_oNodeAllocator); // Default constructor. Must be followed by Init(). MovedRegion (Status_t &a_reStatus, typename BaseClass::Allocator &a_rAlloc = BaseClass::Extents::Imp::sm_oNodeAllocator); // Initializing constructor. Creates an empty region. MovedRegion (Status_t &a_reStatus, const MovedRegion &a_rOther); // Copy constructor. void Init (Status_t &a_reStatus); // Initializer. Must be called on default-constructed // regions. void Assign (Status_t &a_reStatus, const MovedRegion &a_rOther); // Make the current region a copy of the other region. virtual ~MovedRegion(); // Destructor. inline void SetMotionVector (PIXELINDEX a_tnX, PIXELINDEX a_tnY); // Set the motion vector. inline void GetMotionVector (PIXELINDEX &a_rtnX, PIXELINDEX &a_rtnY) const; // Get the motion vector. // Comparison class, suitable for Set<>. class SortBySizeThenMotionVectorLength { public: inline bool operator() (const MovedRegion *a_pLeft, const MovedRegion *a_pRight) const; }; inline FRAMESIZE GetSquaredMotionVectorLength (void) const; // Get the squared length of the motion vector. // Needed by SortBySizeThenMotionVectorLength. private: PIXELINDEX m_tnX, m_tnY; // The motion vector associated with this region. FRAMESIZE m_tnSquaredLength; // The squared length of the motion vector. // Used for sorting. };private: PIXELINDEX m_tnWidth, m_tnHeight; // The dimension of each reference frame. PIXELINDEX m_tnPGW, m_tnPGH; // The dimension of pixel groups. PIXELINDEX m_tnX, m_tnY; // The index of the current pixel group. Actually the index // of the top-left pixel in the current pixel group. This // gets moved in a zigzag pattern, back and forth across the // frame and then down, until the end of the frame is reached. PIXELINDEX m_tnStepX; // Whether we're zigging or zagging. // A region under construction. Contains a MovedRegion that's // known to be on the border between the searched area and the // not-yet-searched area. // If two regions being constructed get merged, one is modified to // point to the other's contained MovedRegion, and they're put into // a doubly-linked-list with each other. // When there are no more references to a region, and it has no // siblings in the doubly-linked list, that means the region is no // longer on the border, and can be handed back to the // search-border's client. class RegionUnderConstruction : public DoublyLinkedList<RegionUnderConstruction> { public: MovedRegion *m_pRegion; // The region being constructed. FRAMESIZE m_tnReferences; // The number of beginnings/endings of extents of this // region that are on the border. When this goes to zero, // and we have no siblings in the doubly-linked-list, then // that means no other matches could possibly be added to // the region, and m_pRegion will get handed back to the // search-border's client. RegionUnderConstruction(); // Default constructor. ~RegionUnderConstruction(); // Destructor. private: typedef DoublyLinkedList<RegionUnderConstruction> BaseClass; // Keep track of who our base class is.#ifndef NDEBUG // Count the number of region objects in existence. private: static uint32_t sm_ulInstances; public: static uint32_t GetInstances (void) { return sm_ulInstances; } #endif // NDEBUG }; // A class that keeps track of region extents on the border between // the searched area and the not-yet-searched area, i.e. the only // regions that have a chance of growing. class BorderExtentBoundary { public: PIXELINDEX m_tnIndex; // The index of the endpoint of an extent. PIXELINDEX m_tnLine; // The vertical line on which this endpoint resides. // Used to quickly tell current-border endpoints apart from // last-border endpoints, and for no other reason. bool m_bIsEnding; // false if this is the beginning of an extent, true if // it's the end of an extent. BorderExtentBoundary *m_pCounterpart; // The ending to go with this beginning, or the beginning to // go with this ending. RegionUnderConstruction *m_pRegion; // The region with the given extent. PIXELINDEX m_tnMotionX, m_tnMotionY; // The region's motion vector. Copied here so that our sort // order doesn't depend on m_pRegion's contents, i.e. so // that we thrash memory less. BorderExtentBoundary(); // Default constructor. BorderExtentBoundary (PIXELINDEX a_tnIndex, PIXELINDEX a_tnLine, bool a_bIsEnding, RegionUnderConstruction *a_pRegion); // Initializing constructor. ~BorderExtentBoundary(); // Destructor.#ifndef NDEBUG bool operator == (const BorderExtentBoundary &a_rOther) const; // Equality operator.#endif // NDEBUG // Comparison class, suitable for Set<>. class SortByIndexThenTypeThenMotionVectorThenRegionAddress { public: inline bool operator() (const BorderExtentBoundary &a_rLeft, const BorderExtentBoundary &a_rRight) const; }; // Comparison class, suitable for Set<>. class SortByMotionVectorThenTypeThenRegionAddress { public: inline bool operator() (const BorderExtentBoundary &a_rLeft, const BorderExtentBoundary &a_rRight) const; }; }; typedef Set<BorderExtentBoundary, typename BorderExtentBoundary ::SortByIndexThenTypeThenMotionVectorThenRegionAddress> BorderExtentBoundarySet; BorderExtentBoundarySet m_setBorderStartpoints, m_setBorderEndpoints; // The borders, i.e. the startpoint/endpoints for every // region under construction, for every line in the current // pixel-group's vertical extent. typename BorderExtentBoundarySet::ConstIterator *m_paitBorderStartpoints, *m_paitBorderEndpoints; // The next last/current-border startpoints/endpoints whose // regions will be added or removed, when we move left or right. // (m_tnPGH + 1 iterators allocated for each.) typedef Set<BorderExtentBoundary, typename BorderExtentBoundary ::SortByMotionVectorThenTypeThenRegionAddress> IntersectingRegionsSet; IntersectingRegionsSet m_setBorderRegions; // All regions that could possibly intersect the current pixel // group, should a match be found. Sorted by motion vector, // since matches must be added to a region with the exact same // motion vector. There may be more than one such region; that // means the current match causes those regions to be contiguous // and thus they will get merged together. // (Note that this set is also sorted by type, i.e. whether // it's a beginning or end. We only put beginnings into this // set. This extra sort criteria is used to help us find the // range of regions that all have the same motion vector, to let // us set up an umambiguous upper-bound for the search.)#ifndef NDEBUGpublic: static uint32_t GetRegionUnderConstructionCount (void) { return RegionUnderConstruction::GetInstances(); }#endif // NDEBUG};// Default constructor.template <class PIXELINDEX, class FRAMESIZE>SearchBorder<PIXELINDEX,FRAMESIZE>::SearchBorder(){ // No frame dimensions yet. m_tnWidth = m_tnHeight = PIXELINDEX (0); // No active search yet. m_tnX = m_tnY = m_tnStepX = PIXELINDEX (0);}// Destructor.template <class PIXELINDEX, class FRAMESIZE>SearchBorder<PIXELINDEX,FRAMESIZE>::~SearchBorder(){ // Make sure our client didn't stop in the middle of a frame. assert (m_setBorderStartpoints.Size() == 0); assert (m_setBorderEndpoints.Size() == 0); assert (m_setBorderRegions.Size() == 0); // Free up our arrays of iterators. delete[] m_paitBorderStartpoints; delete[] m_paitBorderEndpoints;}// Initializer.template <class PIXELINDEX, class FRAMESIZE>voidSearchBorder<PIXELINDEX,FRAMESIZE>::Init (Status_t &a_reStatus, PIXELINDEX a_tnWidth, PIXELINDEX a_tnHeight, PIXELINDEX a_tnPGW, PIXELINDEX a_tnPGH){ // Make sure they didn't start us off with an error. assert (a_reStatus == g_kNoError); // Make sure the width & height are reasonable. assert (a_tnWidth > PIXELINDEX (0)); assert (a_tnHeight > PIXELINDEX (0)); // Initialize the sets that implement our border-regions. m_setBorderStartpoints.Init (a_reStatus, true); if (a_reStatus != g_kNoError) return; m_setBorderEndpoints.Init (a_reStatus, true); if (a_reStatus != g_kNoError) return; m_setBorderRegions.Init (a_reStatus, false); if (a_reStatus != g_kNoError) return; // Allocate space for our iterators into the startpoint/endpoint // sets. (These move left/right/down with the current pixel-group, // and run over regions that get added/removed from the border // regions set.) m_paitBorderStartpoints = new typename BorderExtentBoundarySet::ConstIterator[a_tnPGH + 1]; m_paitBorderEndpoints = new typename BorderExtentBoundarySet::ConstIterator[a_tnPGH + 1]; if (m_paitBorderStartpoints == NULL || m_paitBorderEndpoints == NULL) { delete[] m_paitBorderStartpoints; delete[] m_paitBorderEndpoints; return; } // Finally, store our parameters. m_tnWidth = a_tnWidth;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?