Можно ли в Quartz 2D замаскировать изображение, удалив все, кроме нужного цветового канала?
-
06-09-2019 - |
Вопрос
Поэтому я попытался использовать функцию 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;
}
затем вызовите метод изменения цвета для события нажатия кнопки и посмотрите результат
Другие советы
Я нашел ответ на свою вышеуказанную проблему. Следуйте приведенному выше коду Рахула с некоторыми изменениями, чтобы установить свой собственный цвет.
-(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 — в основном маскируется только черный цвет (т. е. триплеты 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
должен правильно отображать изображение, используя любой из приведенных выше блоков кода.
Следующий ответ немного приближается к тому, что просит ФП, но он касается визуального эффекта, а не реальных данных.Здесь соответствующий код в 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;предполагается, что формат пикселя — 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;
}
Хорошее резюме побитовых операций можно найти здесь.
Как указано здесь, вам может потребоваться изменить структуру маски в зависимости от порядка младшего/старшего битов в пикселе.В этом примере предполагается, что 32-битные пиксели взяты из стандартного PNG-изображения iPhone.