Quartz 2D에서 원하는 색상 채널을 제외한 모든 것을 제거하여 이미지를 마스크하는 것이 가능합니까?

StackOverflow https://stackoverflow.com/questions/913719

문제

그래서 저는 Quartz CGImageCreateWithMaskingColors 함수를 사용하려고 시도했지만 유일한 문제는 선택한 색상 범위를 마스크한다는 것입니다.

선택한 색상 범위를 제외한 모든 것을 마스크하고 싶습니다.예를 들어, 사진에 빨간색만 모두 표시하고 다른 채널(녹색 및 파란색)은 제거하고 싶습니다.

저는 Objective-C에서 이 작업을 수행하고 있으며 초보이므로 예를 들어주세요 :)

어떤 도움이라도 대단히 감사하겠습니다.

도움이 되었습니까?

해결책

이 방법을 사용하여 SO 게시물 중 하나에서 찾았습니다.

-(void)changeColor
{
    UIImage *temp23=Image;//Pass your image here
    CGImageRef ref1=[self createMask:temp23];
    const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
    CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
    UIImage *resultedimage=[UIImage imageWithCGImage:New];
    EditImageView.image = resultedimage;
    [EditImageView setNeedsDisplay];
}

-(CGImageRef)createMask:(UIImage*)temp
{


    CGImageRef ref=temp.CGImage;
    int mWidth=CGImageGetWidth(ref);
    int mHeight=CGImageGetHeight(ref);
    int count=mWidth*mHeight*4;
    void *bufferdata=malloc(count);

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4, colorSpaceRef, kCGImageAlphaPremultipliedFirst); 

    CGRect rect = {0,0,mWidth,mHeight};
    CGContextDrawImage(cgctx, rect, ref); 
    bufferdata = CGBitmapContextGetData (cgctx);

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferdata, mWidth*mHeight*4, NULL);
    CGImageRef savedimageref = CGImageCreate(mWidth,mHeight, 8, 32, mWidth*4, colorSpaceRef, bitmapInfo,provider , NULL, NO, renderingIntent);
    CFRelease(colorSpaceRef);
    return savedimageref;
}

그런 다음 버튼에서 changecolor 메소드를 호출하고 이벤트를 클릭하고 결과를 확인하십시오.

다른 팁

위의 문제에 대한 답을 찾았습니다. 위의 Rahul 코드를 따르십시오.

-(void)changeColor
{
    UIImage *temp23=Image;//Pass your image here
    CGImageRef ref1=[self createMask:temp23];
    const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
    CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
    UIImage *resultedimage=[UIImage imageWithCGImage:New];
    EditImageView.image = resultedimage;
    [EditImageView setNeedsDisplay];
}

-(CGImageRef)createMask:(UIImage*)temp
{
   CGImageRef ref=temp.CGImage;
   int mWidth=CGImageGetWidth(ref);
   int mHeight=CGImageGetHeight(ref);
   int count=mWidth*mHeight*4;
   void *bufferdata=malloc(count);

   CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
   CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
   CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

   CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4,colorSpaceRef, kCGImageAlphaPremultipliedLast); 
   CGRect rect = {0,0,mWidth,mHeight};  
   CGContextDrawImage(cgctx, rect, ref); 
   CGContextSaveGState(cgctx);  
   CGContextSetBlendMode(cgctx, kCGBlendModeColor); 
   CGContextSetRGBFillColor (cgctx, 1.0, 0.0, 0.0, 1.0);
   CGContextFillRect(cgctx, rect);


   bufferdata = CGBitmapContextGetData (cgctx);
   const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
   CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferdata, mWidth*mHeight*4, NULL);
   CGImageRef savedimageref = CGImageCreate(mWidth,mHeight, 8, 32, mWidth*4, colorSpaceRef, bitmapInfo,provider , NULL, NO, renderingIntent);
   CFRelease(colorSpaceRef);
   return savedimageref;
}

흠...

뭔가 빠졌을 수도 있지만 제공된 답변이 질문에 적용된다고 생각하지 않습니다.두 번째 응답은 목표에 가까워지지만 솔루션과 거의 관련이 없는 가짜 코드를 포함하고 있습니다.

그만큼 createMask 이 메서드는 LSB 위치의 알파를 가정하여 원본 이미지의 복사본을 만듭니다.ChangeColor는 RGB 이미지에 큰 영향을 주지 않는 마스킹 호출을 수행합니다. 기본적으로 검은색만 마스킹됩니다(예: (1,1,2) ~ (3, 2,1)).

나는 관찰되는 적색편이가 매개변수에 의한 것이라고 추측하고 있습니다.

kCGImageAlphaPremultipliedFirst

줄에

CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4, colorSpaceRef, kCGImageAlphaPremultipliedFirst);

알파 채널의 부적절한 처리로 인해.만약에 changeColor 블록을 수정하는 방법

CGImageRef ref1=[self createMask:temp23];
const float colorMasking[6] = {1.0, 3.0, 1.0, 2.0, 2.0, 3.0};
CGImageRef New=CGImageCreateWithMaskingColors(ref1, colorMasking);
UIImage *resultedimage=[UIImage imageWithCGImage:New];
EditImageView.image = resultedimage;

장차 ~ 가 되는

CGImageRef ref1=[self createMask:temp23];
UIImage *resultedimage=[UIImage imageWithCGImage:ref];
EditImageView.image = resultedimage;

디스플레이에는 아무런 차이가 없습니다.CGBitmapInfo 상수를 다음으로 변경합니다. kCGImageAlphaPremultipliedLast 위의 코드 블록 중 하나를 사용하여 이미지를 올바르게 표시해야 합니다.

다음 응답은 OP가 요구하는 것과 조금 더 가까워지지만 실제 데이터가 아닌 시각적 효과 측면에서 그렇습니다.여기에 관련 코드가 있습니다. createMask ~이다

CGContextRef cgctx = CGBitmapContextCreate (bufferdata,mWidth,mHeight, 8,mWidth*4,colorSpaceRef, kCGImageAlphaPremultipliedLast);

이미지를 올바르게 표시한 다음

CGContextSetBlendMode(cgctx, kCGBlendModeColor); 
CGContextSetRGBFillColor (cgctx, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(cgctx, rect);

그런 다음 이미지를 구성하는 논리입니다.혼합 논리는 원본 이미지에 빨간색 색조를 오버레이하여 원본 응답에서 잘못 배치된 알파 채널과 유사한 효과를 얻습니다.이것은 여전히 ​​OP가 요구하는 것이 아닙니다. 즉, 색상을 혼합하는 것이 아니라 하나 이상의 채널을 마스크하는 것입니다.

이는 실제로 원하지 않는 색상의 채널 값을 0으로 설정하는 것과 같습니다.다음은 OP 요청에 따라 빨간색 채널만 반환하는 예입니다.픽셀의 형식이 ABGR이라고 가정합니다.

- (CGImageRef) redChannel:(CGImageRef)image 
{
    CGDataProviderRef provider = CGImageGetDataProvider(image);
    NSMutableData* data = (id)CGDataProviderCopyData(provider);

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

    [data autorelease];

    // get a mutable reference to the image data
    uint32_t* dwords = [data mutableBytes];

    for (size_t idx = 0; idx < width*height; idx++) {
        uint32_t* pixel = &dwords[idx];
        // perform a logical AND of the pixel with a mask that zeroes out green and blue pixels
        *pixel &= 0x000000ff;
    }

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // now create a new image using the masked original data
    CGDataProviderRef iprovider = CGDataProviderCreateWithData(NULL, dwords, width*height*4, NULL);
    CGImageRef savedimageref = CGImageCreate(width, height, 8, 32, width*4, colorSpaceRef, bitmapInfo, iprovider, NULL, NO, renderingIntent);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(iprovider);

    return savedimageref;
}

비트 연산에 대한 좋은 요약을 찾을 수 있습니다. 여기.

지적한 바와 같이 여기, 픽셀 비트의 LSB/MSB 순서에 따라 마스크 구조를 변경해야 할 수도 있습니다.이 예에서는 표준 iPhone PNG의 32비트 픽셀을 가정합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top