problem in drawing line - iphone

brushSize=1.0f;
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)]; //originally self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapButt); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushSize);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 1.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x+brushSize*4,lastPoint.y-brushSize);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x-brushSize, lastPoint.y+brushSize*4);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I am using this Code for drawing......In touchesmoved.
i do getting gaps when iam drawing fastly... what to do?

You should use UITouch's previousLocationInView: method to get the previous known point you finger was and draw a line between that point and the current location.
Another solution is to keep the currentPoint in a static variable between two calls.

CGContextBeginPath(Mycontext);
CGContextMoveToPoint(Mycontext, lastPoint.x, lastPoint.y);
int x, cx, deltax, xstep,y, cy, deltay, ystep,error, st, dupe;
int x0, y0, x1, y1;
x0 = currentPoint.x;
y0 = currentPoint.y;
x1 = lastPoint.x;
y1 = lastPoint.y;
// find largest delta for pixel steps
st = (abs(y1 - y0) > abs(x1 - x0));
// if deltay > deltax then swap x,y
if (st) {
(x0 ^= y0); (y0 ^= x0); (x0 ^= y0); // swap(x0, y0);
(x1 ^= y1); (y1 ^= x1); (x1 ^= y1); // swap(x1, y1);
}
deltax = abs(x1 - x0);
deltay = abs(y1 - y0);
error = (deltax / 2);
y = y0;
if (x0 > x1) { xstep = -1; }
else { xstep = 1; }
if (y0 > y1) { ystep = -1; }
else { ystep = 1; }
for ((x = x0); (x != (x1 + xstep)); (x += xstep))
{
(cx = x); (cy = y); // copy of x, copy of y
// if x,y swapped above, swap them back now
if (st) { (cx ^= cy); (cy ^= cx); (cx ^= cy); }
(dupe = 0); // initialize no dupe
if(!dupe) {
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), cx+brushSize*4,cy-brushSize);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), cx-brushSize, cy+brushSize*4);
}
(error -= deltay); // converge toward end of line
if (error < 0) { // not done yet
(y += ystep);
(error += deltax);
}
}
CGContextStrokePath(Mycontext);
Image_Cookie.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;

Related

How to find the closing path(two line intersection) in iPhone SDK?

Please see the image. How can I get the two line intersection point(that is green rounded point)? I want to crop the inner part of the image. The closing path is any where in the line.
context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
CGContextSetLineWidth(context, 1.0 * self.scale);
CGContextSetLineCap(context, kCGLineCapRound);
[[UIColor redColor] setStroke];
CGPoint firstPoint = CGPointFromString([self.touchPoints objectAtIndex:0]);
CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
for (NSString *pointString in self.touchPoints) {
CGPoint point = CGPointFromString(pointString);
CGContextAddLineToPoint(context, point.x, point.y);
}
CGContextStrokePath(context);
This code used for the draw the lines. Line drawing is working fine, cropping also working fine...But the intersection point is my major problem. Please help me.
Idea, check for intersections beginning with firstline<>lastline, firstline<>secondlastline ... firstline<>thirdline => secondline<>lastline etc. This should give you the outer most intersection.
The following Code is not tested, but should help you with your problem.
typedef struct {
CGPoint startPoint;
CGPoint endPoint;
} Line;
#define CGPointNULL CGPointMake(NAN, NAN)
#define Line(_i_) {CGPointFromString(touchPoints[_i_-1]), CGPointFromString(touchPoints[_i_])};
CGPoint LineIntersects(Line *first, Line *second) {
int x1 = first->startPoint.x; int y1 = first->startPoint.y;
int x2 = first->endPoint.x; int y2 = first->endPoint.y;
int x3 = second->startPoint.x; int y3 = second->startPoint.y;
int x4 = second->endPoint.x; int y4 = second->endPoint.y;
int d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4);
if (d == 0) return CGPointNULL;
int xi = ((x3-x4)*(x1*y2-y1*x2)-(x1-x2)*(x3*y4-y3*x4))/d;
int yi = ((y3-y4)*(x1*y2-y1*x2)-(y1-y2)*(x3*y4-y3*x4))/d;
return CGPointMake(xi,yi);
}
static inline BOOL CGPointIsValid(CGPoint p) {
return (p.x != NAN && p.y != NAN);
}
- (CGPoint)mostOuterIntersection:(NSArray *)touchPoints {
CGPoint intersection = CGPointNULL;
int touchCount = [touchPoints count];
for(int i = 1; i<touchCount; i++) {
Line first = Line(i);
for(int j = touchCount-1; j>i+1; j--) {
Line last = Line(j);
intersection = LineIntersects(&first, &last);
if(CGPointIsValid(intersection)) {
break;
}
}
}
return intersection;
}

Detect paper as series of points with OpenCV

I'm attempting to detect a piece of paper in a photo on the iPhone using OpenCV. I'm using the code from this question: OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
Here's the code:
- (void)findEdges {
image = [[UIImage imageNamed:#"photo.JPG"] retain];
Mat matImage = [image CVMat];
find_squares(matImage, points);
UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
[imageView setFrame:CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height)];
[self addSubview:imageView];
[imageView setAlpha:0.3f];
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 0.8);
CGFloat scaleX = self.frame.size.width / image.size.width;
CGFloat scaleY = self.frame.size.height / image.size.height;
// Draw the detected squares.
for( vector<vector<cv::Point> >::const_iterator it = points.begin(); it != points.end(); it++ ) {
vector<cv::Point> square = *it;
cv::Point p1 = square[0];
cv::Point p2 = square[1];
cv::Point p3 = square[2];
cv::Point p4 = square[3];
CGContextBeginPath(context);
CGContextMoveToPoint(context, p1.x * scaleX, p1.y * scaleY); //start point
CGContextAddLineToPoint(context, p2.x * scaleX, p2.y * scaleY);
CGContextAddLineToPoint(context, p3.x * scaleX, p3.y * scaleY);
CGContextAddLineToPoint(context, p4.x * scaleX, p4.y * scaleY); // end path
CGContextClosePath(context);
CGContextSetLineWidth(context, 4.0);
CGContextStrokePath(context);
}
}
double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
void find_squares(Mat& image, vector<vector<cv::Point> >& squares) {
// blur will enhance edge detection
Mat blurred(image);
medianBlur(image, blurred, 9);
Mat gray0(blurred.size(), CV_8U), gray;
vector<vector<cv::Point> > contours;
// find squares in every color plane of the image
for (int c = 0; c < 3; c++)
{
int ch[] = {c, 0};
mixChannels(&blurred, 1, &gray0, 1, ch, 1);
// try several threshold levels
const int threshold_level = 2;
for (int l = 0; l < threshold_level; l++)
{
// Use Canny instead of zero threshold level!
// Canny helps to catch squares with gradient shading
if (l == 0)
{
Canny(gray0, gray, 10, 20, 3); //
// Dilate helps to remove potential holes between edge segments
dilate(gray, gray, Mat(), cv::Point(-1,-1));
}
else
{
gray = gray0 >= (l+1) * 255 / threshold_level;
}
// Find contours and store them in a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Test contours
vector<cv::Point> approx;
for (size_t i = 0; i < contours.size(); i++)
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)))
{
double maxCosine = 0;
for (int j = 2; j < 5; j++)
{
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
if (maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
}
Here's the input image:
Here's the result:
What am I doing wrong?

Draw Brush Is Not Completly Drawing When Moving Diagonally?

When drawing from currentPoint.x and currentPoint.y to lastPoint.x and lastPoint.y
in diagonally right upside or right downwards it's giving me gaps (spaces) in the drawn line as shown in below image.
-(void)brushType{
UIGraphicsBeginImageContext(drawImage.frame.size);
CGContextRef Mycontext = UIGraphicsGetCurrentContext();
int x, cx, deltax, xstep,y, cy, deltay, ystep,error, st, dupe;
int x0, y0, x1, y1;
x0 = currentPoint.x;
y0 = currentPoint.y;
x1 = lastPoint.x;
y1 = lastPoint.y;
// find largest delta for pixel steps
st =(abs(y1 - y0) > abs(x1 - x0));
// if deltay > deltax then swap x,y
if (st) {
(x0 ^= y0);
(y0 ^= x0);
(x0 ^= y0); //swap(x0, y0);
(x1 ^= y1);
(y1 ^= x1);
(x1 ^= y1); // swap(x1, y1);
}
deltax = abs(x1 - x0);
deltay = abs(y1 - y0);
error = (deltax / 4);
y = y0;
if (x0 > x1) {
xstep = -1;
}
else {
xstep = 1;
}
if (y0 > y1) {
ystep = -1;
}
else {
ystep = 1;
}
for ((x = x0); (x != (x1 + xstep)); (x += xstep))
{
(cx = x);
(cy = y); // copy of x, copy of y
// if x,y swapped above, swap them back now
if (st) {
(cx ^= cy);
(cy ^= cx);
(cx ^= cy);
}
(dupe = 0); // initialize no dupe
if(!dupe) {
CGContextSetRGBStrokeColor(Mycontext, 0.0, 0.0, 0.0, 1.00f);
CGContextMoveToPoint(Mycontext, cx+brushSize*4,cy-brushSize/2);
CGContextAddLineToPoint(Mycontext, cx-brushSize/2, cy+brushSize*4);
}
(error -= deltay); // converge toward end of line
if (error < 0) { // not done yet
(y += ystep);
(error += deltax);}
}
CGContextStrokePath(Mycontext);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)];
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
brushSize = 4;
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:drawImage];
currentPoint.y -= 20;
[self brushType];
}
If anyone has an idea please helpe me to fix this issue!
I see a bunch of problems with your function, most of which are poor style. You are using XOR-swap, which makes the code hard to read. You declare all of your variables at the top of the method, making it harder to understand the lifetime of each variable. You put unnecessary parentheses all over the place, making the code harder to read. You call CGContextSetRGBStrokeColor repeatedly in your loop, but you only need to set the stroke color once. So first let's rewrite your method to fix those problems:
static inline void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
-(void)brushType {
int x0 = currentPoint.x;
int y0 = currentPoint.y;
int x1 = lastPoint.x;
int y1 = lastPoint.y;
int deltax = abs(x1 - x0);
int deltay = abs(y1 - y0);
int needSwap = deltay > deltax;
if (needSwap) {
swap(&x0, &y0);
swap(&x1, &y1);
swap(&deltax, &deltay);
}
int error = deltax / 4;
int y = y0;
int xstep = x0 > x1 ? -1 : 1;
int ystep = y0 > y1 ? -1 : 1;
CGSize size = self.drawImage.bounds.size;
UIGraphicsBeginImageContext(size); {
CGContextRef gc = UIGraphicsGetCurrentContext();
for (int x = x0; x != x1 + xstep; x += xstep)
{
int cx = x;
int cy = y;
if (needSwap)
swap(&cx, &cy);
CGContextMoveToPoint(gc, cx + brushSize*4, cy - brushSize/2);
CGContextAddLineToPoint(gc, cx - brushSize/2, cy + brushSize*4);
error -= deltay; // converge toward end of line
if (error < 0) { // not done yet
y += ystep;
error += deltax;
}
}
[UIColor.blackColor setStroke];
CGContextStrokePath(gc);
[self.drawImage.image drawInRect:CGRectMake(0, 0, size.width, size.height)];
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
} UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
So now it's easier to understand that you're stepping along the straight line from lastPoint to currentPoint. If that line is primarily horizontal, you increment x by 1 (or -1) at each step, and increment y as necessary to stay close to the true straight line. If the line is primarily vertical, you swap x and y.
Here's the problem. Suppose the straight line is at a 45 degree angle. You're going to increment x by 1 and y by 1 at every step. Pythagoras tells us that you're moving a distance of sqrt(2) ≈ 1.4142 points per step. Since your “brush” is stroked with the default stroke width of 1 point, there's a gap between adjacent stamps of the brush.
The correct way to fix this is to stop using ints and error correction terms to compute the points along the line. Core Graphics and UIKit use CGFloats anyway, so by using ints you're not only getting less accurate results, you're triggering extra conversions from CGFloat to int and back.
What you need to do is store x and y as CGFloat, and increment them both at each step so that the distance between brush stamps is 1.
-(void)brushType {
CGFloat dx = currentPoint.x - lastPoint.x;
CGFloat dy = currentPoint.y - lastPoint.y;
CGFloat length = hypotf(dx, dy);
dx /= length;
dy /= length;
CGSize size = self.drawImage.bounds.size;
// Bonus! This works correctly on Retina devices!
UIGraphicsBeginImageContextWithOptions(size, NO, self.drawImage.window.screen.scale); {
CGContextRef gc = UIGraphicsGetCurrentContext();
for (CGFloat i = 0; i < length; ++i) {
CGFloat x = lastPoint.x + i * dx;
CGFloat y = lastPoint.y + i * dy;
CGContextMoveToPoint(gc, x + brushSize * 4, y - brushSize / 2);
CGContextAddLineToPoint(gc, x - brushSize / 2, y + brushSize * 4);
}
[UIColor.blackColor setStroke];
CGContextSetLineWidth(gc, 1.01);
CGContextStrokePath(gc);
[self.drawImage.image drawAtPoint:CGPointZero];
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
} UIGraphicsEndImageContext();
lastPoint = currentPoint;
}
If you use this version of the method, you'll find that it looks much better, but still not quite perfect:
The problem, I believe, is that diagonal strokes are drawn using anti-aliasing, and anti-aliasing is an approximation. If you drawn two width-1 lines 1 point apart, the partial colorings that each line contributes to the common pixels don't add up perfectly.
An easy, cheesy way to fix it is to make your stroke width a little wider. Just add this before CGContextStrokePath:
CGContextSetLineWidth(gc, 1.1);
Result:

UIView rounded corners Question

Whats wrong with this code?
-(void) drawRect:(CGRect) rect {
CGContextRef c = UIGraphicsGetCurrentContext();
if (c != nil) {
CGContextSetFillColorWithColor(c, self.cornerColor.CGColor);
[self drawRoundedCornersInRect:self.bounds inContext:c];
CGContextFillPath(c);
}
}
-(void) drawCornerInContext:(CGContextRef)c cornerX:(int) x cornerY:(int) y
arcEndX:(int) endX arcEndY:(int) endY {
CGContextMoveToPoint(c, x, endY);
CGContextAddArcToPoint(c, x, y, endX, y, radius);
CGContextAddLineToPoint(c, x, y);
CGContextAddLineToPoint(c, x, endY);
}
-(void) drawRoundedCornersInRect:(CGRect) rect inContext:(CGContextRef) c {
int x_left = rect.origin.x;
int x_left_center = rect.origin.x + radius;
int x_right_center = rect.origin.x + rect.size.width - radius;
int x_right = rect.origin.x + rect.size.width;
int y_top = rect.origin.y;
int y_top_center = rect.origin.y + radius;
int y_bottom_center = rect.origin.y + rect.size.height - radius;
int y_bottom = rect.origin.y + rect.size.height;
if (roundUpperLeft) {
[self drawCornerInContext:c cornerX: x_left cornerY: y_top
arcEndX: x_left_center arcEndY: y_top_center];
}
if (roundUpperRight) {
[self drawCornerInContext:c cornerX: x_right cornerY: y_top
arcEndX: x_right_center arcEndY: y_top_center];
}
if (roundLowerRight) {
[self drawCornerInContext:c cornerX: x_right cornerY: y_bottom
arcEndX: x_right_center arcEndY: y_bottom_center];
}
if (roundLowerLeft) {
[self drawCornerInContext:c cornerX: x_left cornerY: y_bottom
arcEndX: x_left_center arcEndY: y_bottom_center];
}
}
No errors, No warnings ... but the round corners don't work at all. I found this code here.
You need to begin a path, and close it when you're done. Your 2nd call to CGContextAddLineToPoint messes things up I think. Here's a snippet that works. Study it and enhance it to support your multiple cases (it seems that you want to be able to round only some corners, and not necessarily all of them...)
void addRoundedRect(CGContextRef ctx, CGRect rect, float cornerRadius) {
if (cornerRadius <= 2.0) {
CGContextAddRect(ctx, rect);
} else {
float x_left = rect.origin.x;
float x_left_center = x_left + cornerRadius;
float x_right_center = x_left + rect.size.width - cornerRadius;
float x_right = x_left + rect.size.width;
float y_top = rect.origin.y;
float y_top_center = y_top + cornerRadius;
float y_bottom_center = y_top + rect.size.height - cornerRadius;
float y_bottom = y_top + rect.size.height;
/* Begin path */
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, x_left, y_top_center);
/* First corner */
CGContextAddArcToPoint(ctx, x_left, y_top, x_left_center, y_top, cornerRadius);
CGContextAddLineToPoint(ctx, x_right_center, y_top);
/* Second corner */
CGContextAddArcToPoint(ctx, x_right, y_top, x_right, y_top_center, cornerRadius);
CGContextAddLineToPoint(ctx, x_right, y_bottom_center);
/* Third corner */
CGContextAddArcToPoint(ctx, x_right, y_bottom, x_right_center, y_bottom, cornerRadius);
CGContextAddLineToPoint(ctx, x_left_center, y_bottom);
/* Fourth corner */
CGContextAddArcToPoint(ctx, x_left, y_bottom, x_left, y_bottom_center, cornerRadius);
CGContextAddLineToPoint(ctx, x_left, y_top_center);
/* Done */
CGContextClosePath(ctx);
}
}
I use this: [view.layer setCornerRadius:7];. It sets the corner radius using the UIView's CALayer backer.

How to draw line between two points with animation?

I have used the code below for drawing a line between two points.
#define PI 3.14159
CGContextBeginPath(ctx);
int x;
for(int y=rect.origin.y; y < rect.size.height; y++)
{
x = ((rect.size.width/4) * sin(((y*4) % 360) * PI/180)) + rect.size.width/2;
if(y == 0)
{
CGContextMoveToPoint(ctx, x, y);
}
else
{
CGContextAddLineToPoint(ctx, x, y);
}
}
CGContextStrokePath(ctx);
But I want to implement this with animation. How would it be possible? Can you help me?