use of georegression.struct.point.Point2D_I32 in project BoofCV by lessthanoptimal.
the class SplitMergeLineFitLoop method selectSplitOffset.
/**
* Finds the point between indexStart and the end point which is the greater distance from the line
* (set up prior to calling). Returns the index of the element with a distances greater than tolerance, otherwise -1
*
* @return Selected offset from start of the split. -1 if no split was selected
*/
protected int selectSplitOffset(int indexStart, int length) {
int bestOffset = -1;
int indexEnd = (indexStart + length) % N;
Point2D_I32 startPt = contour.get(indexStart);
Point2D_I32 endPt = contour.get(indexEnd);
line.p.set(startPt.x, startPt.y);
line.slope.set(endPt.x - startPt.x, endPt.y - startPt.y);
double bestDistanceSq = splitThresholdSq(contour.get(indexStart), contour.get(indexEnd));
// adjusting using 'minimumSideLengthPixel' to ensure it doesn't create a new line which is too short
// 1 is the minimum so that you don't split on the same corner
int minLength = Math.max(1, minimumSideLengthPixel);
length -= minLength;
for (int i = minLength; i <= length; i++) {
Point2D_I32 b = contour.get((indexStart + i) % N);
point2D.set(b.x, b.y);
double dist = Distance2D_F64.distanceSq(line, point2D);
if (dist >= bestDistanceSq) {
bestDistanceSq = dist;
bestOffset = i;
}
}
return bestOffset;
}
use of georegression.struct.point.Point2D_I32 in project BoofCV by lessthanoptimal.
the class ShapeFittingOps method averageCircle_I32.
/**
* Computes a circle which has it's center at the mean position of the provided points and radius is equal to the
* average distance of each point from the center. While fast to compute the provided circle is not a best
* fit circle by any reasonable metric, except for special cases.
*
* @param points (Input) Set of unordered points. Not modified.
* @param optional (Optional) Used internally to store the distance of each point from the center. Can be null.
* @param outputStorage (Output/Optional) Storage for results. If null then a new circle instance will be returned.
* @return The found circle fit.
*/
public static FitData<Circle2D_F64> averageCircle_I32(List<Point2D_I32> points, GrowQueue_F64 optional, FitData<Circle2D_F64> outputStorage) {
if (outputStorage == null) {
outputStorage = new FitData<>(new Circle2D_F64());
}
if (optional == null) {
optional = new GrowQueue_F64();
}
Circle2D_F64 circle = outputStorage.shape;
int N = points.size();
// find center of the circle by computing the mean x and y
int sumX = 0, sumY = 0;
for (int i = 0; i < N; i++) {
Point2D_I32 p = points.get(i);
sumX += p.x;
sumY += p.y;
}
optional.reset();
double centerX = circle.center.x = sumX / (double) N;
double centerY = circle.center.y = sumY / (double) N;
double meanR = 0;
for (int i = 0; i < N; i++) {
Point2D_I32 p = points.get(i);
double dx = p.x - centerX;
double dy = p.y - centerY;
double r = Math.sqrt(dx * dx + dy * dy);
optional.push(r);
meanR += r;
}
meanR /= N;
circle.radius = meanR;
// compute radius variance
double variance = 0;
for (int i = 0; i < N; i++) {
double diff = optional.get(i) - meanR;
variance += diff * diff;
}
outputStorage.error = variance / N;
return outputStorage;
}
use of georegression.struct.point.Point2D_I32 in project BoofCV by lessthanoptimal.
the class MergeRegionMeanShift method markMergeRegions.
/**
* Takes the mode of a region and searches the local area around it for other regions. If the region's mode
* is also within the local area its color is checked to see if it's similar enough. If the color is similar
* enough then the two regions are marked for merger.
*/
protected void markMergeRegions(FastQueue<float[]> regionColor, FastQueue<Point2D_I32> modeLocation, GrayS32 pixelToRegion) {
for (int targetId = 0; targetId < modeLocation.size; targetId++) {
float[] color = regionColor.get(targetId);
Point2D_I32 location = modeLocation.get(targetId);
int x0 = location.x - searchRadius;
int x1 = location.x + searchRadius + 1;
int y0 = location.y - searchRadius;
int y1 = location.y + searchRadius + 1;
// ensure that all pixels it examines are inside the image
if (x0 < 0)
x0 = 0;
if (x1 > pixelToRegion.width)
x1 = pixelToRegion.width;
if (y0 < 0)
y0 = 0;
if (y1 > pixelToRegion.height)
y1 = pixelToRegion.height;
// look at the local neighborhood
for (int y = y0; y < y1; y++) {
for (int x = x0; x < x1; x++) {
int candidateId = pixelToRegion.unsafe_get(x, y);
// see if it is the same region
if (candidateId == targetId)
continue;
// see if the mode is near by
Point2D_I32 p = modeLocation.get(candidateId);
if (p.distance2(location) <= maxSpacialDistanceSq) {
// see if the color is similar
float[] candidateColor = regionColor.get(candidateId);
float colorDistance = SegmentMeanShiftSearch.distanceSq(color, candidateColor);
if (colorDistance <= maxColorDistanceSq) {
// mark the two regions as merged
markMerge(targetId, candidateId);
}
}
}
}
}
}
use of georegression.struct.point.Point2D_I32 in project BoofCV by lessthanoptimal.
the class MergeSmallRegions method checkAdjacentAround.
private void checkAdjacentAround(int x, int y, int indexImg, GrayS32 pixelToRegion) {
int regionA = pixelToRegion.data[indexImg];
for (int i = 0; i < connect.length; i++) {
Point2D_I32 p = connect[i];
if (!pixelToRegion.isInBounds(x + p.x, y + p.y))
continue;
int regionB = pixelToRegion.data[indexImg + p.y * pixelToRegion.stride + p.x];
if (regionA != regionB) {
boolean pruneA = segmentPruneFlag.data[regionA];
boolean pruneB = segmentPruneFlag.data[regionB];
if (pruneA) {
Node n = pruneGraph.get(segmentToPruneID.get(regionA));
n.connect(regionB);
}
if (pruneB) {
Node n = pruneGraph.get(segmentToPruneID.get(regionB));
n.connect(regionA);
}
}
}
}
use of georegression.struct.point.Point2D_I32 in project BoofCV by lessthanoptimal.
the class SegmentMeanShiftSearchGray method findPeak.
/**
* Uses mean-shift to find the peak. Returns the peak as an index in the image data array.
*
* @param gray The color value which mean-shift is trying to find a region which minimises it
*/
protected void findPeak(float cx, float cy, float gray) {
history.reset();
history.grow().set(cx, cy);
for (int i = 0; i < maxIterations; i++) {
float total = 0;
float sumX = 0, sumY = 0, sumGray = 0;
int kernelIndex = 0;
float x0 = cx - radiusX;
float y0 = cy - radiusY;
// If it is not near the image border it can use faster techniques
if (interpolate.isInFastBounds(x0, y0) && interpolate.isInFastBounds(x0 + widthX - 1, y0 + widthY - 1)) {
for (int yy = 0; yy < widthY; yy++) {
for (int xx = 0; xx < widthX; xx++) {
float ds = spacialTable[kernelIndex++];
float pixelGray = interpolate.get_fast(x0 + xx, y0 + yy);
float dc = pixelGray - gray;
dc = dc * dc / maxColorDistanceSq;
float weight = dc > 1 ? 0 : weight((ds + dc) / 2f);
total += weight;
sumX += weight * (xx + x0);
sumY += weight * (yy + y0);
sumGray += weight * pixelGray;
}
}
} else {
// Perform more sanity checks here for the image edge. Edge pixels are handled by skipping them
for (int yy = 0; yy < widthY; yy++) {
float sampleY = y0 + yy;
// make sure it is inside the image
if (sampleY < 0) {
kernelIndex += widthX;
continue;
} else if (sampleY > image.height - 1) {
break;
}
for (int xx = 0; xx < widthX; xx++, kernelIndex++) {
float sampleX = x0 + xx;
// make sure it is inside the image
if (sampleX < 0 || sampleX > image.width - 1) {
continue;
}
float ds = spacialTable[kernelIndex];
float pixelGray = interpolate.get(x0 + xx, y0 + yy);
float dc = pixelGray - gray;
dc = dc * dc / maxColorDistanceSq;
float weight = dc > 1 ? 0 : weight((ds + dc) / 2f);
total += weight;
sumX += weight * (xx + x0);
sumY += weight * (yy + y0);
sumGray += weight * pixelGray;
}
}
}
if (total == 0)
break;
float peakX = sumX / total;
float peakY = sumY / total;
if (fast) {
history.grow().set(peakX, peakY);
// see if it has already been here before
int px = (int) (peakX + 0.5f);
int py = (int) (peakY + 0.5f);
int index = pixelToMode.getIndex(px, py);
int modeIndex = pixelToMode.data[index];
if (modeIndex != -1) {
// it already knows the solution so stop searching
Point2D_I32 modeP = modeLocation.get(modeIndex);
this.modeX = modeP.x;
this.modeY = modeP.y;
return;
}
}
float dx = peakX - cx;
float dy = peakY - cy;
cx = peakX;
cy = peakY;
gray = sumGray / total;
if (Math.abs(dx) < convergenceTol && Math.abs(dy) < convergenceTol) {
break;
}
}
this.modeX = cx;
this.modeY = cy;
this.meanGray = gray;
}
Aggregations