Integrated pixy into emulator. Pixy is no longer in the common/libs folder but in emulator/libs and discovery/libs

This commit is contained in:
t-moe
2015-04-03 21:42:46 +02:00
parent c570bda350
commit cab86098c5
68 changed files with 6968 additions and 19 deletions

View File

@@ -0,0 +1,357 @@
//
// begin license header
//
// This file is part of Pixy CMUcam5 or "Pixy" for short
//
// All Pixy source code is provided under the terms of the
// GNU General Public License v2 (http://www.gnu.org/licenses/gpl-2.0.html).
// Those wishing to use Pixy source code, software and/or
// technologies under different licensing terms should contact us at
// cmucam@cs.cmu.edu. Such licensing terms are available for
// all portions of the Pixy codebase presented here.
//
// end license header
//
#ifndef _BLOB_H
#define _BLOB_H
// TODO
//
// *** Priority 1
//
// *** Priority 2:
//
// *** Priority 3:
//
// *** Priority 4:
//
// Think about heap management of CBlobs
// Think about heap management of SLinkedSegments
//
// *** Priority 5 (maybe never do):
//
// Try small and large SMoments structure (small for segment)
// Try more efficient SSegment structure for lastBottom, nextBottom
//
// *** DONE
//
// DONE Compute elongation, major/minor axes (SMoments::GetStats)
// DONE Make XRC LUT
// DONE Use XRC LUT
// DONE Optimize blob assy
// DONE Start compiling
// DONE Conditionally record segments
// DONE Ask rich about FP, trig
// Take segmented image in (DONE in imageserver.cc, ARW 10/7/04)
// Produce colored segmented image out (DONE in imageserver.cc, ARW 10/7/04)
// Draw blob stats in image out (DONE for centroid, bounding box
// in imageserver.cc, ARW 10/7/04)
// Delete segments when deleting blob (DONE, ARW 10/7/04)
// Check to see if we attach to multiple blobs (DONE, ARW 10/7/04)
// Sort blobs according to area (DONE, ARW 10/7/04)
// DONE Sort blobs according to area
// DONE Clean up code
#include <stdlib.h>
#include <assert.h>
//#include <memory.h>
#include <math.h>
//#define INCLUDE_STATS
// Uncomment this for verbose output for testing
//#include <iostream.h>
struct SMomentStats {
int area;
// X is 0 on the left side of the image and increases to the right
// Y is 0 on the top of the image and increases to the bottom
float centroidX, centroidY;
// angle is 0 to PI, in radians.
// 0 points to the right (positive X)
// PI/2 points downward (positive Y)
float angle;
float majorDiameter;
float minorDiameter;
};
// Image size is 352x278
// Full-screen blob area is 97856
// Full-screen centroid is 176,139
// sumX, sumY is then 17222656, 13601984; well within 32 bits
struct SMoments {
// Skip major/minor axis computation when this is false
static bool computeAxes;
int area; // number of pixels
void Reset() {
area = 0;
#ifdef INCLUDE_STATS
sumX= sumY= sumXX= sumYY= sumXY= 0;
#endif
}
#ifdef INCLUDE_STATS
int sumX; // sum of pixel x coords
int sumY; // sum of pixel y coords
// XX, XY, YY used for major/minor axis calculation
long long sumXX; // sum of x^2 for each pixel
long long sumYY; // sum of y^2 for each pixel
long long sumXY; // sum of x*y for each pixel
#endif
void Add(const SMoments &moments) {
area += moments.area;
#ifdef INCLUDE_STATS
sumX += moments.sumX;
sumY += moments.sumY;
if (computeAxes) {
sumXX += moments.sumXX;
sumYY += moments.sumYY;
sumXY += moments.sumXY;
}
#endif
}
#ifdef INCLUDE_STATS
void GetStats(SMomentStats &stats) const;
bool operator==(const SMoments &rhs) const {
if (area != rhs.area) return 0;
if (sumX != rhs.sumX) return 0;
if (sumY != rhs.sumY) return 0;
if (computeAxes) {
if (sumXX != rhs.sumXX) return 0;
if (sumYY != rhs.sumYY) return 0;
if (sumXY != rhs.sumXY) return 0;
}
return 1;
}
#endif
};
struct SSegment {
unsigned char model : 3 ; // which color channel
unsigned short row : 9 ;
unsigned short startCol : 10; // inclusive
unsigned short endCol : 10; // inclusive
const static short invalid_row= 0x1ff;
// Sum 0^2 + 1^2 + 2^2 + ... + n^2 is (2n^3 + 3n^2 + n) / 6
// Sum (a+1)^2 + (a+2)^2 ... b^2 is (2(b^3-a^3) + 3(b^2-a^2) + (b-a)) / 6
//
// Sum 0+1+2+3+...+n is (n^2 + n)/2
// Sum (a+1) + (a+2) ... b is (b^2-a^2 + b-a)/2
void GetMoments(SMoments &moments) const {
int s= startCol - 1;
int e= endCol;
moments.area = (e-s);
#ifdef INCLUDE_STATS
int e2= e*e;
int y= row;
int s2= s*s;
moments.sumX = ( (e2-s2) + (e-s) ) / 2;
moments.sumY = (e-s) * y;
if (SMoments::computeAxes) {
int e3= e2*e;
int s3= s2*s;
moments.sumXY= moments.sumX*y;
moments.sumXX= (2*(e3-s3) + 3*(e2-s2) + (e-s)) / 6;
moments.sumYY= moments.sumY*y;
}
#endif
}
#ifdef INCLUDE_STATS
void GetMomentsTest(SMoments &moments) const;
#endif
};
struct SLinkedSegment {
SSegment segment;
SLinkedSegment *next;
SLinkedSegment(const SSegment &segmentInit) :
segment(segmentInit), next(NULL) {}
};
class CBlob {
// These are at the beginning for fast inclusion checking
public:
static int leakcheck;
CBlob *next; // next ptr for linked list
// Bottom of blob, which is the surface we'll attach more segments to
// If bottom of blob contains multiple segments, this is the smallest
// segment containing the multiple segments
SSegment lastBottom;
// Next bottom of blob, currently under construction
SSegment nextBottom;
// Bounding box, inclusive. nextBottom.row contains the "bottom"
short left, top, right;
void getBBox(short &leftRet, short &topRet,
short &rightRet, short &bottomRet) {
leftRet= left;
topRet= top;
rightRet= right;
bottomRet= lastBottom.row;
}
// Segments which compose the blob
// Only recorded if CBlob::recordSegments is true
// firstSegment points to first segment in linked list
SLinkedSegment *firstSegment;
// lastSegmentPtr points to the next pointer field _inside_ the
// last element of the linked list. This is the field you would
// modify in order to append to the end of the list. Therefore
// **lastSegmentPtr should always equal to NULL.
// When the list is empty, lastSegmentPtr actually doesn't point inside
// a SLinkedSegment structure at all but instead at the firstSegment
// field above, which in turn is NULL.
SLinkedSegment **lastSegmentPtr;
SMoments moments;
static bool recordSegments;
// Set to true for testing code only. Very slow!
static bool testMoments;
CBlob();
~CBlob();
int GetArea() const {
return(moments.area);
}
// Clear blob data and free segments, if any
void Reset();
void NewRow();
void Add(const SSegment &segment);
// This takes futileResister and assimilates it into this blob
//
// Takes advantage of the fact that we are always assembling top to
// bottom, left to right.
//
// Be sure to call like so:
// leftblob.Assimilate(rightblob);
//
// This lets us assume two things:
// 1) The assimilated blob contains no segments on the current row
// 2) The assimilated blob lastBottom surface is to the right
// of this blob's lastBottom surface
void Assimilate(CBlob &futileResister);
// Only updates left, top, and right. bottom is updated
// by UpdateAttachmentSurface below
void UpdateBoundingBox(int newLeft, int newTop, int newRight);
};
// Strategy for using CBlobAssembler:
//
// Make one CBlobAssembler for each color channel.
// CBlobAssembler ignores the model index, so you need to be sure to
// only pass the correct segments to each CBlobAssembler.
//
// At the beginning of a frame, call Reset() on each assembler
// As segments appear, call Add(segment)
// At the end of a frame, call EndFrame() on each assembler
// Get blobs from finishedBlobs. Blobs will remain valid until
// the next call to Reset(), at which point they will be deleted.
//
// To get statistics for a blob, do the following:
// SMomentStats stats;
// blob->moments.GetStats(stats);
// (See imageserver.cc: draw_blob() for an example)
class CBlobAssembler {
short currentRow;
// Active blobs, in left to right order
// (Active means we are still potentially adding segments)
CBlob *activeBlobs;
// Current candidate for adding a segment to. This is a member
// of activeBlobs, and scans left to right as we search the active blobs.
CBlob *currentBlob;
// Pointer to pointer to current candidate, which is actually the pointer
// to the "next" field inside the previous candidate, or a pointer to
// the activeBlobs field of this object if the current candidate is the
// first element of the activeBlobs list. Used for inserting and
// deleting blobs.
CBlob **previousBlobPtr;
public:
// Blobs we're no longer adding to
CBlob *finishedBlobs;
short maxRowDelta;
static bool keepFinishedSorted;
public:
CBlobAssembler();
~CBlobAssembler();
// Call prior to starting a frame
// Deletes any previously created blobs
void Reset();
// Call once for each segment in the color channel
int Add(const SSegment &segment);
// Call at end of frame
// Moves all active blobs to finished list
void EndFrame();
int ListLength(const CBlob *b);
// Split a list of blobs into two halves
void SplitList(CBlob *all, CBlob *&firstHalf, CBlob *&secondHalf);
// Merge maxelts elements from old1 and old2 into newptr
void MergeLists(CBlob *&old1, CBlob *&old2, CBlob **&newptr, int maxelts);
// Sorts finishedBlobs in order of descending area using an in-place
// merge sort (time n log n)
void SortFinished();
// Assert that finishedBlobs is in fact sorted. For testing only.
void AssertFinishedSorted();
protected:
// Manage currentBlob
//
// We always want to guarantee that both currentBlob
// and currentBlob->next have had NewRow() called, and have
// been validated to remain on the active list. We could just
// do this for all activeBlobs at the beginning of each row,
// but it's less work to only do it on demand as segments come in
// since it might allow us to skip blobs for a given row
// if there are no segments which might overlap.
// BlobNewRow:
//
// Tell blob there is a new row of data, and confirm that the
// blob should still be on the active list by seeing if too many
// rows have elapsed since the last segment was added.
//
// If blob should no longer be on the active list, remove it and
// place on the finished list, and skip to the next blob.
//
// Call this either zero or one time per blob per row, never more.
//
// Pass in the pointer to the "next" field pointing to the blob, so
// we can delete the blob from the linked list if it's not valid.
void BlobNewRow(CBlob **ptr);
void RewindCurrent();
void AdvanceCurrent();
int m_blobCount;
};
#endif // _BLOB_H