C# Windows Form Picture Box Drawing With Mouse - java

EDIT: Drawing a 4 pointed star does work now with this code but i don't really know WHY this works, AND if i divide by the same number for x & y it just gives me a diamond??? 3 & 7 seem to be the best values too and i have no idea why...
public AP4Star() { }
public AP4Star(int x1, int y1, int x2, int y2, Color c, bool solid, float penW) : base(x1, y1, x2, y2, c, solid, penW) { }
public override void Draw(Graphics g)
{
float xDisplacement = Math.Abs(getX1() - getX2());
float yDisplacement = Math.Abs(getY1() - getY2());
PointF top = new PointF((getX1() + getX2()) / 2, Math.Min(getY2(), getY1()));
PointF bottom = new PointF(top.X, Math.Max(getY2(), getY1()));
PointF left = new PointF(Math.Min(getX2(), getX1()), (top.Y + bottom.Y) / 2);
PointF right = new PointF(Math.Max(getX2(), getX1()), left.Y);
PointF mtr = new PointF(right.X - xDisplacement / 3, right.Y - yDisplacement / 7);
PointF mbr = new PointF(right.X - xDisplacement / 3, right.Y + yDisplacement / 7);
PointF mbl = new PointF(left.X + xDisplacement / 3, left.Y + yDisplacement / 7);
PointF mtl = new PointF(left.X + xDisplacement / 3, left.Y - yDisplacement / 7);
PointF[] fourStar = { top,mtr, right, mbr, bottom, mbl, left, mtl };
g.DrawPolygon(new Pen(getColor(), getPenWidth()), fourStar);
That code produce a pretty good pointy star but i feel like i am still doing this wrong... : result

I don't think this is really a coding question, it's more of a logic question. But here's how I'd solve it:
Start by zero-indexing all of your points. Assuming all of your points are equidistant from zero, that means n = 10 gives you four points like the following for your initial diamond:
p1: { x = 0, y = 10}
p2: { x = 10, y = 0}
p3: { x = 0, y = -10}
p4: { x = -10, y = 0}
Now just add each of those points with a new point that has n / 4 (if it was n / 2, it'd be a straight line. So n / 4 ... or anything greater than 2, should get you a pointy star). So if we use n/4, you get the following eight points:
p1: { x = 0, y = 10}
p2: { x = 2.5, y = 2.5}
p3: { x = 10, y = 0}
p4: { x = 2.5, y = -2.5}
p5: { x = 0, y = -10}
p6: { x = -2.5, y = -2.5
p7: { x = -10, y = 0}
p8: { x = -2.5, y = 2.5}
Now just draw a line between each of those points and you should have your pointy star. I hope that's helpful!

Related

find intersection point of two vectors independent from direction

I have two vectors and i want to know where these vectors will intersect independent from direction or length. So lets just say i would draw an infinite line in either direction and i want to know where those two lines will intersect and get the coordinates. See image below for clarification:
So i want to know the coordinates of the pink X. But i can only find formulas for calculating the intersection point of two lines with an stard and end point which i dont have :( So i am looking for some help on how to approach this properly.
I have calculated the normalized direction of the blue lines: like so:
PVector norm12 = new PVector(-dir12.y, dir12.x);
PVector norm23 = new PVector(dir23.y, -dir23.x);
Some context on why i want to do this:
I am trying to find the center point of a circle created from 3 points.
All this is in 2D
If extra information is needed i am happy to provide.
If you've a endless line which is defined by a point P and a normalized direction R and a second endless line, which is defined by a point Q and a direction S, then the intersection point of the endless lines X is:
alpha ... angle between Q-P and R
beta ... angle between R and S
gamma = 180° - alpha - beta
h = | Q - P | * sin(alpha)
u = h / sin(beta)
t = | Q - P | * sin(gamma) / sin(beta)
t = dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, S)) / determinant(mat2(R, S))
u = dot(Q-P, (R.y, -R.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, R)) / determinant(mat2(R, S))
X = P + R * t = Q + S * u
This can be calculated by the use of PVector, as follows:
// Intersect 2 endless lines
// line 1: "P" is on endless line, the direction is "dir1" ("R")
// line 2: "Q" is on endless line, the direction is "dir2" ("S")
PVector Intersect( PVector P, PVector dir1, PVector Q, PVector dir2) {
PVector R = dir1.copy();
PVector S = dir2.copy();
R.normalize();
S.normalize();
PVector QP = PVector.sub(Q, P);
PVector SNV = new PVector(S.y, -S.x);
float t = QP.dot(SNV) / R.dot(SNV);
PVector X = PVector.add(P, PVector.mult(R, t));
return X;
}
See the example:
void setup() {
size(500,500);
}
void draw() {
background(0, 0, 0);
stroke(255);
fill(255, 0, 0);
PVector l1p1 = new PVector(250, 150);
PVector l1p2 = new PVector(300, 300);
PVector l2p1 = new PVector(200, 180);
PVector l2p2 = new PVector(300, 220);
PVector l3p1 = new PVector(200, 300);
PVector l3p2 = new PVector(250, 280);
line(l1p1.x, l1p1.y, l1p2.x, l1p2.y);
line(l2p1.x, l2p1.y, l2p2.x, l2p2.y);
line(l3p1.x, l3p1.y, l3p2.x, l3p2.y);
PVector dir1 = PVector.sub(l1p2, l1p1);
PVector dir2 = PVector.sub(l2p2, l2p1);
PVector dir3 = PVector.sub(l3p2, l3p1);
PVector x1 = Intersect(l1p1, dir1, l2p1, dir2);
circle(x1.x, x1.y, 10);
PVector x2 = Intersect(l1p1, dir1, l3p1, dir3);
circle(x2.x, x2.y, 10);
PVector x3 = Intersect(l2p1, dir2, l3p1, dir3);
circle(x3.x, x3.y, 10);
}
Note, if the lines are parallel then the scalars of the returned point (PVector object) are infinit. This can be evaluated by Float.isInfinite. e.g:
if (!Float.isInfinite(x1.x) || !Float.isInfinite(x1.y))
circle(x1.x, x1.y, 10);

How to calculate intersection points based on corners and number of cells

I am trying to find all intersection points (their x and y values) based on 4 corner points that I always have and number of cells (in my case 9, so 9x9 matrix, sudoku puzzle).
My 4 corners are marked with green cross, and taged P1 to P4.
I tried to calculate it, and only managed to do it precisely for the first row.
double xDis = p2.x - p1.x;
double yDis = p2.y - p1.y;
double xW = xDis / 9;
double yH = yDis / 9;
for (int i = 0; i < 10; i++) {
Point point = new Point(p1.x + (i * xW), p1.y + (i * yH));
}
This code would work exactly as I expected it but only for the first row.
What am I missing here ? Is there some kind of algoritmh that already does this ? Any hints are welcome.
Note that I am using android with OpenCV library.
As written above in the comments, I ended up warping the image and then cutting it. It looks something like this
if (points != null) {
Point p1 = points[0];
Point p2 = points[1];
Point p3 = points[2];
Point p4 = points[3];
MatOfPoint2f src = new MatOfPoint2f(
p1,
p2,
p3,
p4);
drawMarker(frame, p1, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p2, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p3, new Scalar(255,0,0), 0, 20, 1);
drawMarker(frame, p4, new Scalar(255,0,0), 0, 20, 1);
double x = p2.x - p1.x;
double y = p3.y - p2.y;
MatOfPoint2f dst = new MatOfPoint2f(
new Point(0, 0),
new Point(x,0),
new Point(0,y),
new Point(x,y)
);
Mat warpMat = Imgproc.getPerspectiveTransform(src, dst);
//This is you new image as Mat
Mat destImage = new Mat();
Imgproc.warpPerspective(bw2, destImage, warpMat, new Size(x, y));
List<Mat> cells = getCells(destImage, destImage.width() / 9, destImage.height / 9);
}
private List<Mat> getCells(Mat m, int width, int height) {
Size cellSize = new Size(width, height);
List<Mat> cells = new ArrayList<>();
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
Rect rect = new Rect(new Point(col * width, row * height), cellSize);
Mat digit = new Mat(m, rect).clone();
cells.add(digit);
}
}
return cells;
}
You only do your calculation once, on the first row.
Put your for loop inside of another for loop and run it 10 times, and you should be good (Adding in whatever x,y translation happens as you traverse downwards in y).
As for if there is any automated way to do this, yes. I could suggest using Harris Corner Detection. I suspect using the right thresholds could get you only the thicker line corners. You could also try doing line detection and looking for intersections.
Also, this article may be helpful if you find you aren't finding good lines/corners. You can correct the shading from the lighting and get a good clean image to analyze.

Corner detection not accurate

I'm trying to detect corners, but the coordinates I get are always off-center and saddle-points are detected Multiple times.
I tried cornerHarris, cornerMinEigenVal, preCornerDetect, goodFeaturesToTrack, and cornerEigenValsAndVecs, but they all seem to lead to the same result. I haven't tried findChessboardCorners because my corners are not laid out in a nice grid of n×m, are not all saddle-type, and many more reasons.
What I have now:
Given the (pre-processed) camera image below with some positive, negative, and saddle corners:
After cornerHarris(img, energy, 20, 9, 0.1) (I increased blockSize to 20 for illustrative purposes but small values don't work either) I get this image:
It seems to detect 10 corners but the way they are positioned is odd. I superimposed this image on the original to show my problem:
The point of highest matching energy is offset towards the inside of the corner and there is a plume pointing away from the corner. The saddle corners seem to generate four separate plumes all superimposed.
Indeed, when I perform a corner-search using this energy image, I get something like:
/
What am I doing wrong and how can I detect corners accurately like in this mock image?
[[edit]] MCVE:
public class CornerTest {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
private static Mat energy = new Mat();
private static Mat idx = new Mat();
public static void main(String... args) {
Mat byteImage = Highgui.imread("KXw7O.png");
if (byteImage.channels() > 1)
Imgproc.cvtColor(byteImage, byteImage, Imgproc.COLOR_BGR2GRAY);
// Preprocess
Mat floatImage = new Mat();
byteImage.convertTo(floatImage, CvType.CV_32F);
// Corner detect
Mat imageToShow = findCorners(floatImage);
// Show in GUI
imageToShow.convertTo(byteImage, CvType.CV_8U);
BufferedImage bufImage = new BufferedImage(byteImage.width(), byteImage.height(), BufferedImage.TYPE_BYTE_GRAY);
byte[] imgArray = ((DataBufferByte)bufImage.getRaster().getDataBuffer()).getData();
byteImage.get(0, 0, imgArray);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new JLabel(new ImageIcon(bufImage)));
frame.pack();
frame.setVisible(true);
}
private static Mat findCorners(Mat image) {
Imgproc.cornerHarris(image, energy, 20, 9, 0.1);
// Corner-search:
int minDistance = 16;
Core.MinMaxLocResult minMaxLoc = Core.minMaxLoc(
energy.submat(20, energy.rows() - 20, 20, energy.rows() - 20));
float thr = (float)minMaxLoc.maxVal / 4;
Mat tmp = energy.reshape(1, 1);
Core.sortIdx(tmp, idx, 16); // 16 = CV_SORT_EVERY_ROW | CV_SORT_DESCENDING
int[] idxArray = new int[idx.cols()];
idx.get(0, 0, idxArray);
float[] energyArray = new float[idx.cols()];
energy.get(0, 0, energyArray);
int n = 0;
for (int p : idxArray) {
if (energyArray[p] == -1) continue;
if (energyArray[p] < thr) break;
n++;
int x = p % image.cols();
int y = p / image.cols();
// Exclude a disk around this corner from potential future candidates
int u0 = Math.max(x - minDistance, 0) - x;
int u1 = Math.min(x + minDistance, image.cols() - 1) - x;
int v0 = Math.max(y - minDistance, 0) - y;
int v1 = Math.min(y + minDistance, image.rows() - 1) - y;
for (int v = v0; v <= v1; v++)
for (int u = u0; u <= u1; u++)
if (u * u + v * v <= minDistance * minDistance)
energyArray[p + u + v * image.cols()] = -1;
// A corner is found!
Core.circle(image, new Point(x, y), minDistance / 2, new Scalar(255, 255, 255), 1);
Core.circle(energy, new Point(x, y), minDistance / 2, new Scalar(minMaxLoc.maxVal, minMaxLoc.maxVal, minMaxLoc.maxVal), 1);
}
System.out.println("nCorners: " + n);
// Rescale energy image for display purpose only
Core.multiply(energy, new Scalar(255.0 / minMaxLoc.maxVal), energy);
// return image;
return energy;
}
}

How do I use ArrayList.get()?

I am writing a program in Processing to make a 3-D scatterplot that one can rotate around in space using PeasyCam. Data is read in from a text file to an ArrayList of PVectors. The entire code is shown below. What I don't understand is that importTextfile() needs to be called (repeatedly) within draw() and this significantly slows things down. Why can't I get away with calling it once within setup()? With "println(pointsList)" within draw() I can see that pointList changes if it's not preceded by importTextFile(). Can anyone explain why?
(Update: From trying to construct a minimum working example I see now that the problem is when I make a PVector V and then write over it to map it to the display window. I would still appreciate feedback on a good work around that involves calling importTextFile() just during setup(). What do I use instead of .get() so I get a copy of what's in the Arraylist and not a pointer to the actually value in the ArrayList?)
Here is the code:
import peasy.*;
PeasyCam cam;
ArrayList <PVector>pointList;
int maxX = 0;
int maxY = 0;
int maxZ = 0;
int minX = 10000;
int minY = 10000;
int minZ = 10000;
int range = 0;
void setup() {
size(500, 500, P3D);
cam = new PeasyCam(this, width/2, width/2, width/2, 800);
cam.setMinimumDistance(100);
cam.setMaximumDistance(2000);
pointList = new ArrayList();
importTextFile();
println(pointList);
//Determine min and max along each axis
for (int i=0; i < pointList.size(); i++) {
PVector R = pointList.get(i);
if (R.x > maxX) {
maxX = (int)R.x;
}
if (R.x < minX) {
minX = (int)R.x;
}
if (R.y > maxY) {
maxY = (int)R.y;
}
if (R.y < minY) {
minY = (int)R.y;
}
if (R.z > maxZ) {
maxZ = (int)R.z;
}
if (R.z < minZ) {
minZ = (int)R.z;
}
}
if (maxX - minX > range) {
range = maxX - minX;
}
if (maxY - minY > range) {
range = maxY - minY;
}
if (maxZ - minZ > range) {
range = maxZ - minZ;
}
println(pointList);
}
void draw() {
//importTextFile(); Uncomment to make run properly
println(pointList);
background(255);
stroke(0);
strokeWeight(2);
line(0, 0, 0, width, 0, 0);
line(0, 0, 0, 0, width, 0);
line(0, 0, 0, 0, 0, width);
stroke(150);
strokeWeight(1);
for (int i=1; i<6; i++) {
line(i*width/5, 0, 0, i*width/5, width, 0);
line(0, i*width/5, 0, width, i*width/5, 0);
}
lights();
noStroke();
fill(255, 0, 0);
sphereDetail(10);
//**The problem is here**
for (int i=0; i < pointList.size(); i++) {
PVector V = pointList.get(i);
V.x = map(V.x, minX-50, minX+range+50, 0, width);
V.y = map(V.y, minY-50, minY+range+50, 0, width);
V.z = map(V.z, minZ-50, minZ+range+50, 0, width);
pushMatrix();
translate(V.x, V.y, V.z);
sphere(4);
popMatrix();
}
}
void importTextFile() {
String[] strLines = loadStrings("positions.txt");
for (int i = 0; i < strLines.length; ++i) {
String[] arrTokens = split(strLines[i], ',');
float xx = float(arrTokens[2]);
float yy = float(arrTokens[1]);
float zz = float(arrTokens[0]);
pointList.add( new PVector(xx,zz,yy) );
}
}
You could continue to refactor, I don't know why they show this way of iterating through ArrayLists in the Processing documentation but here is a go at refactoring it:
float calcV (float n) {
return map (n, minX-50, minX+range+50, 0, width);
}
for (PVector V: pointList) {
pushMatrix();
translate(calcV(V.x), calcV(V.y), calcV(V.z));
sphere(4);
popMatrix();
}
You might consider creating a new Class with a PVector as a field or extending PVector. Daniel Shiffman uses this pattern a lot. Create a Class with a PVector for position, another for velocity, a method to calc the new position per frame and another to draw it out to screen. That gives you a lot of flexibility without having to write a ton of loops, other than one to calc and display the objects in your ArrayList.
As PVector is an object, when you do PVector V = pointList.get(i) you pass the reference for that specific element in pointList, to V. It's address in memory. So now V and pointList.get(number) share the same memory address. Any change in either one will change both, as they are two different pointers to same place.
But, if you do:
PVector V = new PVector(pointList.get(i).x, pointList.get(i).y, pointList.get(i).z);
V will be a new object and things will work as you want, cause now V has it's own memory address. And poinList will remain untouched. Same thing goes for other objects, arrays for instance, try this to see:
int[] one = new int[3];
int[] two = new int[3];
void setup(){
one[0] = 0;
one[1] = 1;
one[2] = 2;
print("one firstPrint -> \n");
println(one);
two = one;
print("two firstPrint -> \n");
println(two);
two[2] = 4;
// we didn't mean to change one, but...
print("one secondPrint -> \n");
println(one);
}
I fixed things with the code below but am still interested in other ways.
for (int i=0; i < pointList.size(); i++) {
PVector V = pointList.get(i);
PVector W = new PVector(0.0, 0.0, 0.0);
W.x = map(V.x, minX-50, minX+range+50, 0, width);
W.y = map(V.y, minY-50, minY+range+50, 0, width);
W.z = map(V.z, minZ-50, minZ+range+50, 0, width);
pushMatrix();
translate(W.x, W.y, W.z);
sphere(4);
popMatrix();
}

Detecting Hough circles android

I am trying to detect circles using android. I succeeded to implement the detect lines algorithm but nothing gets displayed when trying the draw hough circles algoritm.
Here is my code:
Mat thresholdImage = new Mat(getFrameHeight() + getFrameHeight() / 2, getFrameWidth(), CvType.CV_8UC1);
mYuv.put(0, 0, data);
Imgproc.cvtColor(mYuv, destination, Imgproc.COLOR_YUV420sp2RGB, 4);
Imgproc.cvtColor(destination, thresholdImage, Imgproc.COLOR_RGB2GRAY, 4);
Imgproc.GaussianBlur(thresholdImage, thresholdImage, new Size(9, 9), 2, 2 );
Mat circles = new Mat();
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT, 1d, (double)thresholdImage.height()/70, 200d, 100d);
Log.w("circles", circles.cols()+"");
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[]=circles.get(0,x);
Point center=new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the circle center
Core.circle(destination, center, 3,new Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
Core.circle( destination, center, radius, new Scalar(0,0,255), 3, 8, 0 );
}
You may have got this sorted by now, but a few things. I'd check your circles mat actually has some results; sometimes vCircle seems to come back null; try one of the other versions of HoughCircles:
iCannyUpperThreshold = 100;
iMinRadius = 20;
iMaxRadius = 400;
iAccumulator = 300;
Imgproc.HoughCircles(thresholdImage, circles, Imgproc.CV_HOUGH_GRADIENT,
2.0, thresholdImage.rows() / 8, iCannyUpperThreshold, iAccumulator,
iMinRadius, iMaxRadius);
if (circles.cols() > 0)
for (int x = 0; x < circles.cols(); x++)
{
double vCircle[] = circles.get(0,x);
if (vCircle == null)
break;
Point pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
int radius = (int)Math.round(vCircle[2]);
// draw the found circle
Core.circle(destination, pt, radius, new Scalar(0,255,0), iLineThickness);
Core.circle(destination, pt, 3, new Scalar(0,0,255), iLineThickness);
}
(I swapped your code into mine, renamed some stuff and swapped it back, I think I've got it back so it works...)
B.

Categories