Как стереть часть изображения, когда пользователь прикасается к нему

Моя большая цель состоит в том, чтобы иметь серое поле над изображением, а затем, когда пользователь протирает это серое поле, оно показывает изображение под ним. По сути, как скретч-карта для лотереи. Я сделал кучу поиска в документах, а также на этом сайте, но не могу найти решение.

Ниже приведено просто доказательство концепции для проверки «стирания» изображения в зависимости от того, где пользователь прикасается, но это не работает. :(

У меня есть UIView, который обнаруживает прикосновения, а затем отправляет координаты перемещения в UIViewController, который обрезает изображение в UIImageView, выполнив следующие действия:

- (void) moveDetectedFrom:(CGPoint) from to:(CGPoint) to
{
    UIImage* image = bkgdImageView.image;
    CGSize s = image.size;
    UIGraphicsBeginImageContext(s);
    CGContextRef g = UIGraphicsGetCurrentContext();

    CGContextMoveToPoint(g, from.x, from.y);
    CGContextAddLineToPoint(g, to.x, to.y);
    CGContextClosePath(g);
    CGContextAddRect(g, CGRectMake(0, 0, s.width, s.height));
    CGContextEOClip(g);
    [image drawAtPoint:CGPointZero];
    bkgdImageView.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [bkgdImageView setNeedsDisplay];
}

Проблема в том, что на этот метод касания отправляются нормально, а на оригинале ничего не происходит.

Я неправильно делаю путь клипа? Или?

Не совсем уверен ... поэтому любая помощь, которую вы можете оказать, будет принята с благодарностью.

Заранее спасибо, Джоэл


person Joel    schedule 04.06.2010    source источник


Ответы (2)


Я пытался сделать то же самое много лет назад, используя только Core Graphics, и это можно сделать, но поверьте мне, эффект не такой плавный и мягкий, как ожидает пользователь. Итак, я знал, как работать с OpenCV (Open Computer Vision Library), и, поскольку он был написан на C, я знал, что смогу использовать его на iPhone. Делать то, что вы хотите делать с OpenCV, чрезвычайно просто. Сначала вам нужна пара функций для преобразования UIImage в IplImage, который является типом, используемым в OpenCV для представления изображений всех видов, и наоборот.

+ (IplImage *)CreateIplImageFromUIImage:(UIImage *)image {
CGImageRef imageRef = image.CGImage;
//This is the function you use to convert a UIImage -> IplImage
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

IplImage *iplimage = cvCreateImage(cvSize(image.size.width, image.size.height), IPL_DEPTH_8U, 4);
CGContextRef contextRef = CGBitmapContextCreate(iplimage->imageData, iplimage->width, iplimage->height,
                                                iplimage->depth, iplimage->widthStep,
                                                colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);
CGContextDrawImage(contextRef, CGRectMake(0, 0, image.size.width, image.size.height), imageRef);


CGContextRelease(contextRef);

CGColorSpaceRelease(colorSpace);

return iplimage;}



+ (UIImage *)UIImageFromIplImage:(IplImage *)image {

//Convert a IplImage -> UIImage
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSData * data = [[NSData alloc] initWithBytes:image->imageData length:image->imageSize];
//NSData *data = [NSData dataWithBytes:image->imageData length:image->imageSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGImageRef imageRef = CGImageCreate(image->width, image->height,
                                    image->depth, image->depth * image->nChannels, image->widthStep,
                                    colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault,
                                    provider, NULL, false, kCGRenderingIntentDefault);
UIImage *ret = [[UIImage alloc] initWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
[data release];
return ret;}

Теперь, когда у вас есть обе основные функции, которые вам нужны, вы можете делать со своим IplImage все, что хотите: вот что вам нужно:

+(UIImage *)erasePointinUIImage:(IplImage *)image :(CGPoint)point :(int)r{
//r is the radious of the erasing
    int a = point.x;
 int b = point.y;
 int position;
 int minX,minY,maxX,maxY;
 minX = (a-r>0)?a-r:0;
 minY = (b-r>0)?b-r:0;
 maxX = ((a+r) < (image->width))? a+r : (image->width);
 maxY = ((b+r) < (image->height))? b+r : (image->height);

 for (int i = minX; i < maxX ; i++)
 {
    for(int j=minY; j<maxY;j++)
    {
        position =  ((j-b)*(j-b))+((i-a)*(i-a));
        if (position <= r*r)
        {
            uchar* ptr =(uchar*)(image->imageData) + (j*image->widthStep + i*image->nChannels);
            ptr[1] = ptr[2] = ptr[3] = ptr[4] = 0;
        }
    }
}
UIImage * res = [self UIImageFromIplImage:image]; 
return res;}

Извините за форматирование.

Если вы хотите узнать, как портировать OpenCV на iPhone, Ёсимаса Нива

Если вы хотите проверить приложение, которое в настоящее время работает с OpenCV в AppStore, перейдите по ссылке:Флаги и лица

person jsan    schedule 09.07.2010

Обычно вы хотите рисовать в текущем графическом контексте внутри метода drawRect:, а не просто в любом старом методе. Кроме того, область отсечения влияет только на то, что отрисовывается в текущем графическом контексте. Но вместо того, чтобы вдаваться в то, почему этот подход не работает, я бы предложил сделать это по-другому.

Что бы я сделал, это иметь два взгляда. Один с изображением, а другой с серым цветом, который сделан прозрачным. Это позволяет графическому оборудованию кэшировать изображение вместо того, чтобы пытаться перерисовывать изображение каждый раз, когда вы изменяете заливку серого.

Серый будет подклассом UIView с CGBitmapContext, в который вы будете рисовать, чтобы сделать пиксели, к которым прикасается пользователь, четкими.

Вероятно, есть несколько способов сделать это. Я просто предлагаю один способ выше.

person lucius    schedule 05.06.2010
comment
Спасибо, что указали мне правильное направление. Я изучал это раньше, но не смог найти правильный способ 1) создать растровое изображение ARGB (кажется, что это всегда RGB) и 2) управлять альфа-значением пикселя, когда у меня есть 2D-массив пиксельных данных. Я буду продолжать копать и выкладывать то, что я узнаю. Спасибо. - person Joel; 05.06.2010
comment
Было бы очень удобно, если бы вы опубликовали свое решение, Джоэл. (Или, по крайней мере, соответствующие методы drawRect.) - person livingtech; 10.12.2010