views:

367

answers:

3

Hi,

I already asked this question and Kenny gave me a good answer (many thanks to him), but I still in confusion about the final realization. So, the question is - how to get access to the matrix of the certain pixel in the image.

I translated Kenny's sample to the Objective-C:

- (NSArray *) compute_transform_matrix:(float)X
      Y:(float)Y
      W:(float)W
      H:(float)H 
       x1a:(float)x1a
       y1a:(float)y1a 
       x2a:(float)x2a 
       y2a:(float)y2a 
       x3a:(float)x3a 
       y3a:(float)y3a 
       x4a:(float)x4a 
       y4a:(float)y4a {
float y21 = y2a - y1a,  y32 = y3a - y2a, y43 = y4a - y3a, y14 = y1a - y4a, y31 = y3a - y1a, y42 = y4a - y2a;

float a = -H*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42);
float b = W*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);
float c = H*X*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) - H*W*x1a*(x4a*y32 - x3a*y42 + x2a*y43) - W*Y*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43);

float d = H*(-x4a*y21*y3a + x2a*y1a*y43 - x1a*y2a*y43 - x3a*y1a*y4a + x3a*y2a*y4a);
float e = W*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42);
float f = -(W*(x4a*(Y*y2a*y31 + H*y1a*y32) - x3a*(H + Y)*y1a*y42 + H*x2a*y1a*y43 + x2a*Y*(y1a - y3a)*y4a + x1a*Y*y3a*(-y2a + y4a)) - H*X*(x4a*y21*y3a - x2a*y1a*y43 + x3a*(y1a - y2a)*y4a + x1a*y2a*(-y3a + y4a)));

float g = H*(x3a*y21 - x4a*y21 + (-x1a + x2a)*y43);
float h = W*(-x2a*y31 + x4a*y31 + (x1a - x3a)*y42);
float i = W*Y*(x2a*y31 - x4a*y31 - x1a*y42 + x3a*y42) + H*(X*(-(x3a*y21) + x4a*y21 + x1a*y43 - x2a*y43) + W*(-(x3a*y2a) + x4a*y2a + x2a*y3a - x4a*y3a - x2a*y4a + x3a*y4a)); 
return [NSArray arrayWithObjects:
[NSArray arrayWithObjects:
    [NSNumber numberWithFloat:a],[NSNumber numberWithFloat:b],[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:c],nil],
   [NSArray arrayWithObjects:
    [NSNumber numberWithFloat:d],[NSNumber numberWithFloat:e],[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:f],nil],
   [NSArray arrayWithObjects:
    [NSNumber numberWithFloat:0],[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:1],[NSNumber numberWithFloat:0],nil],
   [NSArray arrayWithObjects:
    [NSNumber numberWithFloat:g],[NSNumber numberWithFloat:h],[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:i],nil],
   nil];
}

And, at the very beginning I create the image bitmap - "imageBitmap":

   - (void) createImageBitmap{
 NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"Demo.png" ofType:nil];
 UIImage *img = [UIImage imageWithContentsOfFile:imagePath];
 CGImageRef image = CGImageRetain(img.CGImage);

 NSUInteger width = CGImageGetWidth(image);
 NSUInteger height = CGImageGetHeight(image);

 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
 unsigned char *rawData = malloc(height * width * 4);
 NSUInteger bytesPerPixel = 4;
 NSUInteger bytesPerRow = bytesPerPixel * width;
 NSUInteger bitsPerComponent = 8;
 CGContextRef imageBitmap = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
 CGColorSpaceRelease(colorSpace);

 CGContextDrawImage(imageBitmap, CGRectMake(0, 0, width, height), image);
}

Then, I suppose, I need to do following:

    for(int x=0;x<width;x++){
  for(int y=0;x<height;y++){
   NSArray* matrixForPoint = [self compute_transform_matrix:x Y:y W:width H:height x1a:0 y1a:0 x2a:width y2a:0 x3a:width y3a:height x4a:0 y4a:height];
   // set Matrix for x, y point to "imageBitmap" bitmap, but HOW?????????
  }
 }

So, how to set Matrix for x, y point to "imageBitmap" bitmap?

Many thanks in advance

A: 

Kenny's solution provides you with a means of generating a CATransform3D which you would then apply to the CALayer or UIView's layer that is hosting the image. You need to assign the matrix elements for that transform with the values you have calculated here. My recommendation would be to have your -compute_transform_matrix: method return a CATransform3D, and replace the last few lines with

CATransform3D skewTransform;
skewTransform.m11 = a;
skewTransform.m12 = b;
skewTransform.m13 = 0;
skewTransform.m14 = c;
skewTransform.m21 = d;
skewTransform.m22 = e;
skewTransform.m23 = 0;
skewTransform.m24 = f;
skewTransform.m31 = 0;
skewTransform.m32 = 0;
skewTransform.m33 = 1;
skewTransform.m34 = 0;
skewTransform.m41 = g;
skewTransform.m42 = h;
skewTransform.m43 = 0;
skewTransform.m44 = i;

return skewTransform;

You can then set this transform on your layer or view's layer to achieve this skew effect.

Brad Larson
ok, so the matrix applied to the whole layer. But if so, what the attributes in the compute_transform_matrix method means? As I understand: H,W - image height, width; x1a, y1a, x2a ... y4a - the coords of the corners; but what is X and Y????
Dmitry
From Kenny's answer: "To obtain the transform to convert a rectangle ((X, Y), (W, H)) to any quadrilateral ((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)), use this function (you may need a transpose):". It appears that (X, Y) is the origin coordinate of the original image (probably (0, 0) in your case).
Brad Larson
A: 

Hi Brad or Dmitry,

Can you post a simple sample code that uses the function above for skewing a layer?

I've tried it but the results I get are very weird. Maybe I'm not passing the right parameters. I don't know.

It would be nice to have a working sample for this because none of the Apple samples cover this interesting topic.

Thanks in advance, Van M.

A: 

Doesn't work for me either :-(

Dom