Tôi có UIImage và muốn thay đổi độ bão hòa khoảng + 10%. Có phương pháp hoặc chức năng tiêu chuẩn nào có thể được sử dụng cho điều này không?Làm cách nào để thay đổi độ bão hòa của UIImage?
Trả lời
Không có gì khá đơn giản. Giải pháp dễ nhất có lẽ là tạo một CGContext trong bộ nhớ với định dạng pixel đã biết, vẽ hình ảnh vào ngữ cảnh đó, sau đó đọc/sửa đổi các pixel trong bộ đệm định dạng đã biết. Tôi không nghĩ rằng CG hỗ trợ một không gian màu với một kênh bão hòa riêng biệt, vì vậy bạn sẽ phải chuyển đổi từ RGB sang HSV hoặc HSL, hoặc thực hiện các phép tính trực tiếp trong không gian RGB.
Một cách để làm việc tính toán trực tiếp trong RGB có thể là một cái gì đó như thế này:
average = (R + G + B)/3;
red_delta = (R - average) * 11/10;
green_delta = (G - average) * 11/10;
blue_delta = (B - average) * 11/10;
R = average + red_delta;
G = average + green_delta;
B = average + blue_delta;
// clip R,G,B to be in 0-255 range
này sẽ di chuyển các kênh mà là ra khỏi nghĩa khoảng 10% xa hơn. Đây là gần như như tăng độ bão hòa, mặc dù nó sẽ cho màu sắc thay đổi cho một số màu.
Bắt đầu với một xem dựa Mẫu đơn đăng ký, tạo một lớp con mới của UIView như vậy:
// header file
@interface DesatView : UIView {
UIImage *image;
float saturation;
}
@property (nonatomic, retain) UIImage *image;
@property (nonatomic) float desaturation;
@end
// implementation file
#import "DesatView.h"
@implementation DesatView
@synthesize image, desaturation;
-(void)setSaturation:(float)sat;
{
saturation = sat;
[self setNeedsDisplay];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor]; // else background is black
desaturation = 0.0; // default is no effect
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, self.bounds.size.height); // flip image right side up
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, rect, self.image.CGImage);
CGContextSetBlendMode(context, kCGBlendModeSaturation);
CGContextClipToMask(context, self.bounds, image.CGImage); // restricts drawing to within alpha channel
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, desaturation);
CGContextFillRect(context, rect);
CGContextRestoreGState(context); // restore state to reset blend mode
}
@end
Bây giờ trong phương pháp viewDidLoad điều khiển quan điểm của bạn, đưa quan điểm trên màn hình và thiết lập nó là bão hòa như thế này:
- (void)viewDidLoad {
[super viewDidLoad];
DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
dv.image = [UIImage imageNamed:@"someImage.png"];
dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
dv.center = CGPointMake(160, 240); // put it mid-screen
dv.desaturation = 0.2; // desaturate by 20%,
[self.view addSubview:dv]; // put it on screen
}
Thay đổi độ bão hòa như thế này:
dv.saturation = 0.8; // desaturate by 80%
Ob viously nếu bạn muốn sử dụng nó bên ngoài của một phương pháp duy nhất, bạn nên làm cho dv một ivar của bộ điều khiển xem. Hi vọng điêu nay co ich.
Dưới đây là triển khai thực hiện tấn công của Bessey (đặt mã này vào danh mục UIImage). Nó không phải là nhanh chóng và nó chắc chắn thay đổi màu sắc, nhưng nó loại công trình.
+ (CGFloat) clamp:(CGFloat)pixel
{
if(pixel > 255) return 255;
else if(pixel < 0) return 0;
return pixel;
}
- (UIImage*) saturation:(CGFloat)s
{
CGImageRef inImage = self.CGImage;
CFDataRef ref = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
UInt8 * buf = (UInt8 *) CFDataGetBytePtr(ref);
int length = CFDataGetLength(ref);
for(int i=0; i<length; i+=4)
{
int r = buf[i];
int g = buf[i+1];
int b = buf[i+2];
CGFloat avg = (r + g + b)/3.0;
buf[i] = [UIImage clamp:(r - avg) * s + avg];
buf[i+1] = [UIImage clamp:(g - avg) * s + avg];
buf[i+2] = [UIImage clamp:(b - avg) * s + avg];
}
CGContextRef ctx = CGBitmapContextCreate(buf,
CGImageGetWidth(inImage),
CGImageGetHeight(inImage),
CGImageGetBitsPerComponent(inImage),
CGImageGetBytesPerRow(inImage),
CGImageGetColorSpace(inImage),
CGImageGetAlphaInfo(inImage));
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ref);
CGContextRelease(ctx);
return [UIImage imageWithCGImage:img];
}
Bất kỳ ai có ý tưởng về cách cải thiện điều này mà không thực hiện chuyển đổi HSV đầy đủ? Hoặc tốt hơn, một triển khai thực sự cho:
- (UIImage*) imageWithHueOffset:(CGFloat)h saturation:(CGFloat)s value:(CGFloat)v
Có bộ lọc CoreImage cho việc này. CIColorControls
Chỉ cần đặt inputSaturation
thành < 1.0 để khử bão hòa hoặc> 1.0 để tăng độ bão hòa ...
ví dụ: Đây là phương pháp tôi đã thêm vào một danh mục trên UIImage
để khử bão hòa một hình ảnh.
-(UIImage*) imageDesaturated {
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *ciimage = [CIImage imageWithCGImage:self.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
[filter setValue:ciimage forKey:kCIInputImageKey];
[filter setValue:@0.0f forKey:kCIInputSaturationKey];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return image;
}
+1. Tôi nghĩ rằng điều này có khả năng rò rỉ 'cgImage', mặc dù chèn' CFAutorelease (cgImage); 'trước khi' return' sửa lỗi đó. Bạn cũng có thể sử dụng 'kCIInputImageKey' và' kCIInputSaturationKey' thay vì '@" inputImage "' và '@" inputSaturation "' và '@ 0.0f' thay vì' [NSNumber numberWithFloat: 0.0f] '. – Isaac
Cảm ơn @Isaac, đã cập nhật các đề xuất của bạn. –
Mike, tôi đề nghị bạn sử dụng 'UIImage * image = [Hình ảnh UIImageWithCGImage: cgImage scale: self.scale orientation: self.imageOrientation];' vì nó đảm bảo quy mô và hướng được duy trì từ bản gốc, đặc biệt quan trọng khi xử lý thiết bị võng mạc. – devios1
Tôi vừa thử nghiệm phương pháp Mike Pollard 's và nó là đúng.
Đây là nhanh chóng 3 phiên bản
let ciimage = CIImage.init(cgImage: self.givenImage.cgImage)
let filter = CIFilter.init(name: "CIColorControls")
filter?.setValue(ciimage, forKey: kCIInputImageKey)
filter?.setValue(0.0, forKey: kCIInputSaturationKey)
let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
let cgimage = CIContext.init(options: nil).createCGImage(result, from: result.extent)
let image = UIImage.init(cgImage: cgimage!)
- 1. JQuery thay đổi màu sắc, độ bão hòa, gamma của <img>?
- 2. Bổ sung độ bão hòa bitwise trong C (HW)
- 3. Thuật toán nào mà Photoshop sử dụng để khử bão hòa một hình ảnh?
- 4. Cách tốt nhất để tìm kiếm giá trị bão hòa trong danh sách được sắp xếp
- 5. HTML5 - Thay đổi độ mờ đục của một trận hòa Rectangle
- 6. Thay đổi kích thước đơn giản của UIImage trong XCODE
- 7. Làm cách nào để chuyển đổi FBProfilePictureView thành UIImage?
- 8. Làm thế nào để thay đổi độ rộng của html.DropDownListFor()
- 9. Chế độ hòa trộn Android
- 10. Thay đổi kích cỡ UIImage và thay đổi kích thước của UIImageView
- 11. Làm cách nào để giải thể hoạt ảnh khi thay đổi chế độ xem trên iphone?
- 12. Sửa đổi độ mờ đục alpha của biến LESS
- 13. Chuyển đổi tọa độ UIImageView Chạm vào Tọa độ UIImage
- 14. Làm cách nào để thay đổi kích thước của UICollectionView?
- 15. iPhone: Cách thay đổi màu sắc của một pixel cụ thể của UIImage?
- 16. Làm mờ UIImage khi thay đổi thanh trượt
- 17. Làm cách nào để thay đổi độ dài của text_field trong đường ray?
- 18. Làm cách nào để thay đổi mức độ ưu tiên của một quy trình?
- 19. Làm cách nào để thay đổi độ phân giải của raster bằng GDAL?
- 20. three.js - Làm cách nào để tự động thay đổi độ mờ của đối tượng?
- 21. Tôi làm cách nào để thay đổi độ dày của đường trong canvas HTML?
- 22. jqPlot - Làm cách nào để thay đổi độ mờ đục hoặc z-index của canvasOverlay?
- 23. màu tổng hợp: Chế độ hòa trộn và chế độ hòa trộn trên iPhone
- 24. Cách dễ nhất/nhanh nhất để áp dụng chế độ hòa trộn giữa hai UIViews
- 25. Làm cách nào để thay đổi khung textLabel của ô?
- 26. Làm cách nào để thay đổi màu chữ của sectionIndexTitlesForTableView?
- 27. Làm cách nào để thay đổi vị trí của MessageBox?
- 28. Làm cách nào để thay đổi màu của textView android.R.layout.simple_spinner_dropdown_item?
- 29. Làm cách nào để thay đổi hình ảnh của PictureBox?
- 30. Làm cách nào để biến CVPixelBuffer thành UIImage?
Tại sao không chỉ cần gọi [tự setNeedsDisplay] trong setter cho bão hòa? –
Não của tôi tránh xa việc ghi đè bộ tổng hợp cho một số lý do không rõ nhưng bạn đúng. Tôi sẽ thay đổi câu trả lời. – willc2
Vì vậy, điều này làm giảm độ bão hòa, làm thế nào bạn sẽ _increase_ bão hòa? – Shizam