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

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;
}

Related

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:

drawRect not responding

I am trying to draw a pentagon with a set of points storing in a NSArrary, however, the view is empty without any error...
-(void)prepareVertex:(int)noOfVertex
{
polygonPoint=[NSMutableArray arrayWithCapacity:noOfVertex];
for(int i=0;i<noOfVertex;i++)
{
CGPoint point=CGPointMake(sin((2*M_PI)*i/noOfVertex),(cos(2*M_PI)*i/noOfVertex));
[polygonPoint addObject:[NSValue valueWithCGPoint:point]];
NSValue *tempVal=[polygonPoint objectAtIndex:i];
CGPoint tempPoint=[tempVal CGPointValue];
NSLog(#"%f,%f",tempPoint.x,tempPoint.y);
}
}
- (void)drawRect:(CGRect)rect
{
[self prepareVertex:5];
for (int i=0; i<5; i++) {
NSValue *tempVal=[polygonPoint objectAtIndex:i];
CGPoint tempPoint=[tempVal CGPointValue];
}
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextMoveToPoint(context, [[polygonPoint objectAtIndex:0] CGPointValue].x, [[polygonPoint objectAtIndex:0] CGPointValue].x);
for (int i=1; i<5; i++) {
CGPoint point=[[polygonPoint objectAtIndex:i] CGPointValue];
CGContextAddLineToPoint(context,point.x, point.y);
}
CGContextStrokePath(context);
}
Can anyone tell me whats going on??
Well, the first think to note is that you use black to stroke the polygon, so if your view background is black too, you can't see any thing.
Then, and I think this is the real problem, sin(x) and cos(x) are always between -1 and 1, so the points you generate in:
CGPoint point=CGPointMake(sin((2*M_PI)*i/noOfVertex),(cos(2*M_PI)*i/noOfVertex));
are all located in the rectangle CGrectMake(-1, -1, 2, 2). And that area of your view is very probably hidden by the status bar.
So, if the coordinates you generated are what you are looking for are correct, you may try to remove the status bar or change the coordinates of your view. But I think What you should really do is change the previous line into something like this:
CGFloat x = centerPoint.x + radius * sin(2*M_PI*i/noOfVertex);
CGFloat y = centerPoint.y + radius * cos(2*M_PI*i/noOfVertex);
CGPoint point = CGPointMake(x, y);
It draws something in the upper left corner of the view. The figure is just too small to see easily. That's because the values in polygonPoint (btw you should at least call the array polygonPoints) are between -1.0 and 1.0. You have to translate your points to the center of the view and scale the size accordingly.
Something like
- (void)drawRect:(CGRect)rect {
[self prepareVertex:5];
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGFloat x = self.center.x + self.bounds.size.width * 0.5 * [[polygonPoint objectAtIndex:0] CGPointValue].x;
CGFloat y = self.center.y + self.bounds.size.height * 0.5 * [[polygonPoint objectAtIndex:0] CGPointValue].y;
NSLog(#"Point %f/%f", x, y);
CGContextMoveToPoint(context, x, y);
for (int i=1; i<5; i++) {
CGPoint point=[[polygonPoint objectAtIndex:i] CGPointValue];
x = self.center.x + self.bounds.size.width * 0.5 * point.x;
y = self.center.y + self.bounds.size.height * 0.5 * point.y;
NSLog(#"Point %f/%f", x, y);
CGContextAddLineToPoint(context, x, y);
};
CGContextStrokePath(context);
}
does the trick.

CoreText,Copy&Paste

I want use UIMenuController in CoreText,but I can't select the words,I think I must compute the coordinate of the words,but the coordinate can't be correspondence with NSRange.Is there any function to solve it?
Sorry my English is not good~
Here is my code
CFArrayRef lines = CTFrameGetLines(leftFrame);
CFIndex i, total = CFArrayGetCount(lines);
CGFloat y;
for (i = 0; i < total; i++) {
CGPoint origins;
CTFrameGetLineOrigins( leftFrame, CFRangeMake(i, 1), &origins);
CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
y = self.bounds.origin.y + self.bounds.size.height - origins.y;
//CTLineDraw(line, UIGraphicsGetCurrentContext());
CFArrayRef runs = CTLineGetGlyphRuns(line);
CFIndex r, runsTotal = CFArrayGetCount(runs);
//NSLog(#"runsTotal = %d",runsTotal);
for (r = 0; r < runsTotal; r++) {
CGRect runBounds = CTRunGetImageBounds(CFArrayGetValueAtIndex(runs, r), context, CFRangeMake(0, 0));
NSLog(#"runBounds.x = %f,runBounds.y = %f",runBounds.origin.x,runBounds.origin.y);
CFIndex index = CTRunGetStringRange(CFArrayGetValueAtIndex(runs, r)).location;
//NSLog(#"%d",index);
}
}
You can use a tap gesture to get the tap position,
and you have the CTFrame,
Then You can have the needed text frame calculated.
Here is an example , how to calculate two character's frame of the tap position .
pass in CTFrame and Tap Point, get two character's frame and its range in the CTFrame
+(CGRect)parserRectWithPoint:(CGPoint)point range:(NSRange *)selectRange frameRef:(CTFrameRef)frameRef
{
CFIndex index = -1;
CGPathRef pathRef = CTFrameGetPath(frameRef);
CGRect bounds = CGPathGetBoundingBox(pathRef);
CGRect rect = CGRectZero;
// get lines
NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frameRef);
if (!lines) {
return rect;
}
NSInteger lineCount = [lines count];
// prepare for origins of each line
CGPoint *origins = malloc(lineCount * sizeof(CGPoint));
if (lineCount) {
CTFrameGetLineOrigins(frameRef, CFRangeMake(0, 0), origins);
// check tap point in every line
// found, then break
for (int i = 0; i<lineCount; i++) {
CGPoint baselineOrigin = origins[i];
CTLineRef line = (__bridge CTLineRef)[lines objectAtIndex:i];
CGFloat ascent,descent,linegap; //声明字体的上行高度和下行高度和行距
CGFloat lineWidth = CTLineGetTypographicBounds(line, &ascent, &descent, &linegap);
CGRect lineFrame = CGRectMake(baselineOrigin.x, CGRectGetHeight(bounds)-baselineOrigin.y-ascent, lineWidth, ascent+descent+linegap+[LSYReadConfig shareInstance].lineSpace);
if (CGRectContainsPoint(lineFrame,point)){
// line found
CFRange stringRange = CTLineGetStringRange(line);
// glyph found
index = CTLineGetStringIndexForPosition(line, point);
CGFloat xStart = CTLineGetOffsetForStringIndex(line, index, NULL);
CGFloat xEnd;
// choose two words by default
if (index > stringRange.location+stringRange.length-2) {
xEnd = xStart;
xStart = CTLineGetOffsetForStringIndex(line,index-2,NULL);
(*selectRange).location = index-2;
}
else{
xEnd = CTLineGetOffsetForStringIndex(line,index+2,NULL);
(*selectRange).location = index;
}
// choose two character
(*selectRange).length = 2;
rect = CGRectMake(origins[i].x+xStart,baselineOrigin.y-descent,fabs(xStart-xEnd), ascent+descent);
break;
}
}
}
free(origins);
return rect;
}
core-text does not support the text-selection, you need to do it by yourself, please follow the EGOTextView as example

polaroid filter from UIImage

I am trying to implement some image filters, like polaroid, in iphone. I searched on how to filter an existing UIImage to convert it into a polaroid style and come across this stackoverflow link. Taking the answer there as a starting point, I looped through each pixel of the image, taking RGB values, and converted them to HSV, up to this point I have been successful. So this is what I have done (anyone is free to point any mistakes..)
double minRGB(double r, double g, double b){
if (r < g){
if (r < b){
return r;
}else {
return b;
}
}else {
if (g < b){
return g;
}else{
return b;
}
}
}
double maxRGB(double r, double g, double b){
if (r > g){
if (r > b){
return r;
}else {
return b;
}
}else {
if (g > b){
return g;
}else {
return b;
}
}
}
void rgbToHsv(double redIn,double greenIn,double blueIn,double *hue,double *saturation,double* value){
double min,max,delta;
min = minRGB(redIn,greenIn,blueIn);
max = maxRGB(redIn,greenIn,blueIn);
*value = max;
delta = max - min;
if (max != 0) {
*saturation = delta/max;
}else {
*saturation = 0;
*hue = -1.0;
return ;
}
if (redIn == max) {
*hue = (greenIn - blueIn)/delta;
}else if (greenIn == max) {
*hue = 2 + (blueIn - redIn)/delta;
}else {
*hue = 4 + (redIn - greenIn)/delta;
}
*hue *= 60.0;
if (*hue < 0) {
*hue += 360.0;
}
}
void hsvToRgb(double h,double s, double v, double *r,double *g, double *b){
int i;
float f, p, q, t;
if( s == 0 ) {
// achromatic (grey)
*r = *g = *b = v;
return;
}
h /= 60; // sector 0 to 5
i = floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
default: // case 5:
*r = v;
*g = p;
*b = q;
break;
}
}
-(void)makeImagePolaroid:(UIImage*)myImage{
CGImageRef originalImage = [myImage CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL,CGImageGetWidth(originalImage),CGImageGetHeight(originalImage),8,CGImageGetWidth(originalImage)*4,colorSpace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGBitmapContextGetWidth(bitmapContext), CGBitmapContextGetHeight(bitmapContext)), originalImage);
UInt8 *data = CGBitmapContextGetData(bitmapContext);
int numComponents = 4;
int bytesInContext = CGBitmapContextGetHeight(bitmapContext) * CGBitmapContextGetBytesPerRow(bitmapContext);
double redIn, greenIn, blueIn,alphaIn;
double hue,saturation,value;
for (int i = 0; i < bytesInContext; i += numComponents) {
redIn = (double)data[i]/255.0;
greenIn = (double)data[i+1]/255.0;
blueIn = (double)data[i+2]/255.0;
alphaIn = (double)data[i+3]/255.0;
rgbToHsv(redIn,greenIn,blueIn,&hue,&saturation,&value);
hue = hue * 0.7;
if (hue > 360) {
hue = 360;
}
saturation = saturation *1.3;
if (saturation > 1.0) {
saturation = 1.0;
}
value = value * 0.8;
if (value > 1.0) {
value = 1.0;
}
hsvToRgb(hue,saturation,value,&redIn,&greenIn,&blueIn);
data[i] = redIn * 255.0;
data[i+1] = greenIn * 255.0;
data[i+2] = blueIn * 255.0;
}
CGImageRef outImage = CGBitmapContextCreateImage(bitmapContext);
myImage = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return myImage;
}
Now my idea about image processing is very childish (not even amateurish). I read this and tried to adjust the saturation and hue to see if I can get a polaroid effect..I think I am missing something, for I got every effect on earth other than a polaroid (saying that I havent got anything)..
Is there any document on net (or
books) which tells about image
filtering on a programmers point of
view? (and not on a designers point
of view and without a photoshop
screenshot)
What is the hue, saturation, value
difference I have to make on a pixel
so that I can make it polaroid?
And third, Am I on the right track?
Thanks in advance..
This might be helpful, from Camera+ taking filters from photoshop and reproducing them for iOS.
http://taptaptap.com/blog/creating-a-camera-plus-fx/
int step=10;// variable value that changes the level of saturation
int red = pixelRedVal;
int green = pixelGreenVal;
int blue = pixelBlueVal;
int avg = (red + green + blue) / 3;
pixelBuf[r] = SAFECOLOR((avg + step * (red - avg)));
pixelBuf[g] = SAFECOLOR((avg + step * (green - avg)));
pixelBuf[b] = SAFECOLOR((avg + step * (blue - avg)));
where SAFECOLOR is a macro
define SAFECOLOR(color) MIN(255,MAX(0,color))
and for Brightness int step=10;// variable value that changes the level of saturation
int red = pixelRedVal;
int green = pixelGreenVal;
int blue = pixelBlueVal;
pixelBuf[r] = SAFECOLOR(red * step);
pixelBuf[g] = SAFECOLOR(green * step);
pixelBuf[b] = SAFECOLOR(blue * step);
You can simply use this: with different parameters
// Note: the hue input ranges from 0.0 to 1.0, both red. Values outside this range will be clamped to 0.0 or 1.0.
//Polaroid with HSB parameter
- (UIImage*) polaroidishEffectWithHue:(CGFloat)hue saturation:(CGFloat)sat brightness:(CGFloat)bright alpha:(CGFloat)alpha
{
// Find the image dimensions.
CGSize imageSize = [self size];
CGRect imageExtent = CGRectMake(0,0,imageSize.width,imageSize.height);
// Create a context containing the image.
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawAtPoint:CGPointMake(0,0)];
// Draw the hue on top of the image.
CGContextSetBlendMode(context, kCGBlendModeHue);
[[UIColor colorWithHue:hue saturation:sat brightness:bright alpha:alpha] set];
UIBezierPath *imagePath = [UIBezierPath bezierPathWithRect:imageExtent];
[imagePath fill];
// Retrieve the new image.
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}