1

我有两个图像(img1 和 img2)。第一个是固定的,第二个是可拖动的。img1 具有黑色轮廓,其余像素为白色。

示例图片

当我移动 img2 时,它可以与第一个相交。在这里我应该改变非相交部分的像素。所以首先,我使用一种方法来获取特定点的像素。然后,我创建了两种方法来获取两个图像帧的点坐标并将它们保存到两个表中。这两种方法的目的是在拖动img2时比较两个图像的点坐标。我的意思是当我移动 img2 时,我会选择一个位置,它是一个点,并将它与 img1 包含的所有点进行比较。如果该点不包含在 img1 中,我会更改其像素颜色。之后,我比较了两张表,我得到了不常见的点并改变了它的颜色像素。我真的很挣扎。这是我的代码片段:

-(NSMutableArray *) getPixelColorAtLocation:(CGPoint)point
{
    unsigned char pixel[4] = {0};
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast);

    CGContextTranslateCTM(context, -point.x, -point.y);

    [self.view.layer renderInContext:context];
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    NSMutableArray *array = [[NSMutableArray alloc]init];
    [array addObject:[NSString stringWithFormat:@"%d",pixel[0]]];
    [array addObject:[NSString stringWithFormat:@"%d",pixel[1]]];
    [array addObject:[NSString stringWithFormat:@"%d",pixel[2]]];
    [array addObject:[NSString stringWithFormat:@"%d",pixel[3]]];
    return array;
}
-(NSMutableArray *)getimg1Coordinate:(CGPoint)point{

    NSMutableArray *array = [[NSMutableArray alloc]init];
    NSMutableArray *coordinates = [[NSMutableArray alloc]init];
    int c,b;

    for ( c=v.frame.origin.x;c <v.frame.origin.x+v.frame.size.width;c++)
    {
        for(b = v.frame.origin.y ;b<v.frame.origin.y+v.frame.size.height;b++)
        {


            array =[self getPixelColorAtLocation:point];
            int red = [ [array objectAtIndex:0] intValue];
            int green = [ [array objectAtIndex:1] intValue];
            int blue = [ [array objectAtIndex:2] intValue];
            int alpha = [ [array objectAtIndex:3] intValue];

            if( red ==255)
            {
                if( green == 255)
                {
                    if( blue ==255)
                    {
                        if (alpha == 255)
                        {
                            [coordinates addObject:[NSString stringWithFormat:@"%f",point.x]];
                            [coordinates addObject:[NSString stringWithFormat:@"%f",point.y]];
                        }
                    }
                }

            }
        }
    }
return coordinates;
}


-(NSMutableArray *)getImgCoordinate :(CGPoint)point{

    NSMutableArray *coordinates = [[NSMutableArray alloc]init];
    int c,b;

    for ( c=imgView.frame.origin.x;c <imgView.frame.origin.x+imgView.frame.size.width;c++)
    {
        for(b = imgView.frame.origin.y ;b<imgView.frame.origin.y+imgView.frame.size.height;b++)
        {

            [coordinates addObject:[NSString stringWithFormat:@"%f",point.x]];
            [coordinates addObject:[NSString stringWithFormat:@"%f",point.y]];
        }
    }
 return coordinates;
}

我创建了上面的两种方法来存储所有点坐标以获得非公共值。

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *touch = [[event allTouches] anyObject];
    CGPoint location  = [touch locationInView:[self view]];
    // move the image view
    [imgView setCenter:location];
    NSMutableArray *coordImg1 = [[NSMutableArray alloc]init];
    NSMutableArray *coordImg2 = [[NSMutableArray alloc]init];
    coordImg1 = [self getImg1Coordinate:location];
    coordImg2 = [ self getImg2Coordinate:location];

    for (id obj in coordImg) {//each obj in arr2


        if ([coordBubble containsObject:obj])
        {//if arr1 has the same obj(which is from arr2)

        }
        else {
            [self changePixels];

        }

    }

在这里我得到了问题,我怎样才能只得到我应该改变的像素。我不确定我在做什么是最终得到我需要的最好的方法。

- (void)changePixels    {
     CGImageRef imageRef = [img CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = malloc(height * width * 4);
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,kCGImageAlphaPremultipliedFirst| kCGBitmapByteOrder32Big);
     float red = 0.0,green = 0.0,blue = 0.0,alpha = 0.0;
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);
    for(int xx = 0; xx<width; xx++) {
        for(int yy = 0; yy<height; yy++) {
            int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;

            red = rawData[byteIndex];
            green = rawData[byteIndex + 1];
            blue = rawData[byteIndex + 2];
            alpha = rawData[byteIndex + 3];

            if( alpha ==255.000000)
            {
                rawData[byteIndex] = 20;
                rawData[byteIndex+1] = green;
                rawData[byteIndex+2] =  140;
                rawData[byteIndex+3] = 60;
            }

        }
    }

CGContextRef contextref = CGBitmapContextCreate(rawData, width, height,   bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
   UIImage *result = [UIImage imageWithCGImage:CGBitmapContextCreateImage(contextref)];
    CGContextDrawImage(contextref, CGRectMake(0, 0, width, height), imageRef);
    UIImageView *imgV= [[UIImageView alloc]initWithFrame:CGRectMake(0,0,100,100)];
     [imgV setImage:result];
     [self.view addSubview:imgV];
}

我现在正在努力优化我的代码,但目前我只能获取每个图像的坐标,但我还不能更改非公共部分的颜色像素。你知道我应该如何进行吗?

4

1 回答 1

3

您可以使用更高级别的 UIKit 和 Core Graphics 函数,而不是自己尝试逐个像素地执行此操作。考虑下面的最终图像,它是图像和圆形路径的组合,我们使用它来 (a) 遮罩图像和 (b) 描边路径:

带圆圈的小猫

在那种情况下,我可能会:

  1. 以降低的 alpha 绘制图像,以便我们可以在背景中看到它。

  2. 添加蒙版,并在全 Alpha 处重绘蒙版部分。

  3. 如果你需要看到面具的轮廓,也画出来。

这可以通过UIView子视图来实现。首先,定义几个属性:

#import <UIKit/UIKit.h>

@interface MaskedImageView : UIView

@property (nonatomic, strong) UIBezierPath *path;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic) CGRect imageFrame;

@end

然后你可以实现一个drawRect你需要的:

#import "MaskedImageView.h"

@implementation MaskedImageView

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    // draw full image at 50%

    [self.image drawInRect:self.imageFrame blendMode:kCGBlendModeNormal alpha:0.5];

    // draw clipped image at 100%

    CGContextSaveGState(context);
    if (self.path) {
        CGContextAddPath(context, [self.path CGPath]);
        CGContextClip(context);
    }
    [self.image drawInRect:self.imageFrame];
    CGContextRestoreGState(context);

    // now stroke path

    [[UIColor blackColor] setStroke];
    [self.path stroke];
}

- (void)setPath:(UIBezierPath *)path
{
    _path = path;
    [self setNeedsDisplay];
}

- (void)setImage:(UIImage *)image
{
    _image = image;
    [self setNeedsDisplay];
}

- (void)setImageFrame:(CGRect)imageFrame
{
    _imageFrame = imageFrame;
    [self setNeedsDisplay];
}

@end

然后,您可以让您的视图控制器创建此子视图,如下所示:

MaskedImageView *view = [[MaskedImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:view];
view.backgroundColor = [UIColor whiteColor];
UIImage *image = [UIImage imageNamed:@"kitten.jpeg"];
view.image = image;
view.imageFrame = CGRectMake(10, 100, image.size.width, image.size.height);
UIBezierPath *circle = [UIBezierPath bezierPath];
[circle addArcWithCenter:CGPointMake(100,150) radius:80 startAngle:0 endAngle:M_PI * 2.0 clockwise:YES];
circle.lineWidth = 3.0;
view.path = circle;

如果您想将其渲染为UIImage,这是标准技术:

UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[view.layer renderInContext:context];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

如果您想保存该图像:

NSData *data = UIImagePNGRepresentation(newImage);
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *path = [documentsPath stringByAppendingPathComponent:@"test.png"];
[data writeToFile:path atomically:YES];

在上面,我使用蒙版和绘制轮廓的路径。如果您确实需要使用UIImage蒙版而不是路径,您也可以这样做,但您可能需要一张图像作为蒙版,另一张图像作为轮廓。这取决于所需的效果。但是如果掩码是圆形的,使用路径会提供更大的灵活性(并且更容易实现)。


如果您使用图像作为边界(而不是路径),则可以产生如下内容:

在此处输入图像描述

为此,您可能需要两张图片(除了可爱的小猫),即一张(我称之为outlineImage),它仅代表您将在最后添加的笔划。在这张图片中,我将透明背景设为绿色,因此您可以看到我在哪里有透明像素:

中风图像

然后我有另一个图像(我称之为clipImage),它是与上面的图像大小完全相同的蒙版outlineImage(同样,绿色是透明部分):

蒙版图像

然后drawRect看起来像:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    // draw full image at 50%

    [self.image drawInRect:self.imageFrame blendMode:kCGBlendModeNormal alpha:0.5];

    // draw clipped image at 100%

    if (self.clipImage) {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, 0, rect.size.height);
        CGContextScaleCTM(context, 1, -1);
        CGRect clipFrame = self.clipOutlineFrame;
        clipFrame.origin.y = rect.size.height - clipFrame.origin.y - clipFrame.size.height;
        CGContextClipToMask(context, clipFrame, self.clipImage.CGImage);
        CGRect imageframe = self.imageFrame;
        imageframe.origin.y = rect.size.height - imageframe.origin.y - imageframe.size.height;
        CGContextDrawImage(context, imageframe, self.image.CGImage);
        CGContextRestoreGState(context);
    }

    // now draw outline image

    if (self.outlineImage)
        [self.outlineImage drawInRect:self.clipOutlineFrame];
}

然后通过以下方式调用它:

ImageMaskView *view = [[ImageMaskView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:view];
view.backgroundColor = [UIColor whiteColor];
UIImage *image = [UIImage imageNamed:@"kitten.jpeg"];
view.image = image;
view.imageFrame = CGRectMake(10, 100, image.size.width, image.size.height);

view.outlineImage = [UIImage imageNamed:@"loopempty.png"]; // this is the image of the stroke around the masked portion of the underlying image
view.clipImage    = [UIImage imageNamed:@"loopsolid.png"]; // this is the clipping mask (same size as outlineImage)
view.clipOutlineFrame = CGRectMake(20, 110, view.outlineImage.size.width, view.outlineImage.size.height);
于 2013-11-03T13:44:58.940 回答