paint-brush
Cách tạo một ứng dụng để xác định bảng màu và màu chủ đạo của hình ảnhtừ tác giả@denissvinarchuk
406 lượt đọc
406 lượt đọc

Cách tạo một ứng dụng để xác định bảng màu và màu chủ đạo của hình ảnh

từ tác giả Denis Svinarchuk18m2024/03/10
Read on Terminal Reader

dài quá đọc không nổi

Một kỹ thuật quan trọng trong các ứng dụng chỉnh sửa hình ảnh là xác định màu sắc chủ đạo. Việc xác định các màu chủ đạo này là điều cần thiết để tạo bảng màu của hình ảnh, từ đó phản ánh chính xác tác dụng của các công cụ đã chọn và kết quả chỉnh sửa. Bài viết này sẽ đi sâu vào cách xác định bảng màu của hình ảnh trong không gian màu hạn chế, xác định màu chủ đạo của hình ảnh và phân biệt giữa bảng màu và màu chủ đạo.
featured image - Cách tạo một ứng dụng để xác định bảng màu và màu chủ đạo của hình ảnh
Denis Svinarchuk HackerNoon profile picture

Một kỹ thuật quan trọng trong các ứng dụng chỉnh sửa hình ảnh là xác định màu sắc chủ đạo. Việc xác định các màu chủ đạo này là điều cần thiết để tạo bảng màu của hình ảnh, từ đó phản ánh chính xác tác dụng của các công cụ đã chọn và kết quả chỉnh sửa.


Bài viết này sẽ đi sâu vào cách xác định bảng màu của hình ảnh trong không gian màu hạn chế, xác định màu chủ đạo của hình ảnh và phân biệt giữa bảng màu và màu chủ đạo.

Bảng màu

Bảng màu hình ảnh thường là tham chiếu đến tất cả các màu có trong ảnh gốc. Về bản chất, nó thu được toàn bộ phạm vi sắc thái màu, dựa trên thang số của các giá trị tín hiệu kích thích màu.


Nếu chúng ta đồng ý mô hình hóa tín hiệu với mức độ chính xác nhất định thì phạm vi của các giá trị tín hiệu này sẽ thể hiện bảng màu có sẵn của chúng ta.


Mỗi cách thể hiện duy nhất của một hình ảnh và ánh xạ màu của hình ảnh vào không gian này sẽ là một tập hợp con của nó. Trong xử lý tín hiệu số (hình ảnh cũng là tín hiệu), chúng ta thường hiểu nhiều đại lượng khác nhau thông qua biểu diễn rời rạc của nó.


Do đó, bảng hình ảnh của chúng ta có thể được xem như một tập hợp con của tất cả các màu trong ảnh được biểu thị bằng một bản đồ rời rạc. Mỗi màu có thể được lập chỉ mục và gán một giá trị cụ thể trong một trong các không gian màu. Với mục đích của chúng tôi, chúng tôi sẽ sử dụng mô hình màu RGB.


Một thách thức đáng kể trong việc trình bày bảng màu hình ảnh theo cách này là tầm nhìn rộng lớn của con người. Chúng tôi khó có thể phân tích toàn bộ bảng màu hình ảnh theo cách thủ công và việc lưu trữ một hình ảnh được biểu thị bằng tất cả các màu gốc thường không có ý nghĩa gì. Thay vào đó, chúng tôi giảm số lượng của họ xuống một giới hạn hợp lý.


Quá trình này, được gọi là lượng tử hóa màu, bao gồm việc giảm số lượng màu từ tập hợp con đầy đủ có thể được biểu diễn trong một hình ảnh xuống một tập hợp nhỏ hơn. Ví dụ: dữ liệu màu thô 14 bit có thể được biểu diễn dưới dạng JPEG 8 bit hoặc TIFF 16 bit được chuyển đổi thành PNG 8 bit.


Một giải pháp đơn giản để xác định màu cơ bản của hình ảnh là hình dung quá trình lượng tử hóa màu thành một tập hợp rất hạn chế, chẳng hạn như 8 hoặc thậm chí 3 màu. Điều này giúp chúng ta hiểu rõ hơn về các màu cơ bản trong ảnh, khiến chúng dễ nhận thấy và đáng nhớ hơn.


Lý tưởng nhất là màu sắc trong hình ảnh cuối cùng phải hài hòa, tuân theo các nguyên tắc do Johannes Itten hoặc Matyushin vạch ra.


Bằng cách xác định màu sắc chủ đạo của hình ảnh, chúng ta có thể tạo ra một công cụ cho phép chúng ta hình dung "sự hài hòa" của hình ảnh. Điều này cũng có thể áp dụng cho sự hài hòa của hình ảnh sau khi lọc hoặc "sự hài hòa tổng hợp".


Dưới đây, chúng tôi sẽ cố gắng phát triển một công cụ như vậy.

Biểu đồ khối nguồn bảng màu

Cắt trung bình

Thuật toán chất lượng cao và được sử dụng rộng rãi để nén bảng màu của hình ảnh là thuật toán Median Cut. Nó được tích hợp vào hầu hết các thuật toán nén ảnh bị mất dữ liệu lớn, chẳng hạn như JPEG, mặc dù có một số sửa đổi.


Nguyên tắc cơ bản của thuật toán Median Cut là chia tuần tự biểu đồ khối của ảnh thành các số trung vị. Mỗi khối con kết quả chứa một số thùng hoặc pixel có cùng màu xấp xỉ bằng nhau.


Khi quá trình phân chia đạt đến số lượng khối con được xác định trước, chúng tôi sẽ tính toán màu trung bình của mỗi khối và ánh xạ nó tới các màu tương ứng của ảnh gốc. Quá trình này làm giảm số lượng màu trong ảnh gốc một cách hiệu quả, cho phép chúng ta nén ảnh thành kích thước tệp nhỏ hơn.


Thoạt nhìn có vẻ như phần đầu của thuật toán này có thể giải quyết vấn đề của chúng ta trong việc xác định màu chính hoặc màu chủ đạo của hình ảnh. Tuy nhiên, một vấn đề tiềm ẩn có thể nảy sinh khi số lượng màu mà chúng ta chia hình ảnh thành quá ít và chúng ta chỉ phân tích một số lượng nhỏ màu.


Cuối cùng, chúng tôi có thể xác định được các màu không thực sự tồn tại trong ảnh vì các màu này được tính trung bình quá mức. Chúng ta có thể chọn màu có số lượng tối đa từ mỗi khối và gắn nhãn màu đó là màu chủ đạo, nhưng khi đó nó sẽ không còn là bảng màu nữa.


Vì vậy, chúng tôi sẽ bảo lưu phương pháp này để xác định phiên bản nén của bảng màu hình ảnh, phiên bản này cũng có thể được sử dụng làm công cụ phân tích trực quan hình ảnh theo "tiện ích hài hòa" của nó. Để xác định các màu chủ đạo, chúng tôi sẽ sử dụng phân tích thống kê: tìm kiếm cực đại cục bộ trong cùng một biểu đồ hình khối.

Cực đại địa phương

Để xác định cực đại cục bộ, chúng tôi sẽ triển khai một mã cụ thể. Tác giả, cũng là một nghệ sĩ lành nghề, đã đưa ra mô tả tuyệt vời về thuật toán. Về cơ bản, trước tiên chúng tôi thu thập số liệu thống kê hình ảnh vào cùng biểu đồ RGB ba chiều được sử dụng trong thuật toán Median Cut.

Mỗi ô của biểu đồ khối sẽ chứa các thùng màu và tổng tất cả các giá trị của từng màu có trong ô. Với kích thước biểu đồ giới hạn ở độ phân giải 32x32x32 (ban đầu là 30x30x30), việc tích lũy tổng sẽ đơn giản hóa việc tính toán màu trung bình của ô.

Sau đó, chúng tôi tìm kiếm mức tối đa cục bộ bằng cách khám phá toàn bộ không gian và so sánh nó với các ô lân cận.

Theo đó, chúng tôi lặp đi lặp lại giảm số lượng cực đại cục bộ xuống mức cần thiết, loại bỏ các màu tương tự có trọng số thấp hơn. Đối với tất cả các cực đại cục bộ còn lại, chúng tôi tính toán màu trung bình của tất cả các giá trị có trong danh sách.


Vì mật độ màu ở cực đại cục bộ cao hơn và chênh lệch giữa các giá trị pixel nhỏ hơn so với khối từ Median Cut, nên màu sắc sẽ giống với màu có trong hình ảnh chính hơn và sẽ thể hiện chính xác hơn các màu chủ đạo của nó.


Điều này cho thấy sự khác biệt chính giữa hai mô hình: thu được "bảng màu nén" so với việc tìm kiếm các màu chủ đạo hoặc cực đại cục bộ . Bằng cách ánh xạ hình ảnh "bảng nén" chính, chúng tôi sẽ tạo một hình ảnh mới duy trì sự cân bằng màu giống như hình ảnh chính , mặc dù ở dạng bị cắt bớt rất nhiều.


Mặt khác, màu chủ đạo chỉ mô tả bố cục của các màu chủ yếu có trong ảnh . Chúng không thể biến thành bất cứ thứ gì mới với sự cân bằng màu sắc phù hợp.

Thực hiện

Lấy nhiệm vụ này làm ví dụ, chúng tôi sẽ chứng minh việc phát triển một ứng dụng sẵn sàng sử dụng để phân tích và xử lý hình ảnh bằng cách sử dụng Khung công tác IMProcessing dễ dàng như thế nào. Chúng ta sẽ bắt đầu với những chức năng không có trong các công cụ khác.


Chẳng hạn, khung này có khả năng đọc các tệp Adobe .cube với CLUT có sẵn và có thể trích xuất biểu đồ khối ba chiều từ một hình ảnh trong thời gian thực.


Tận dụng điều này, chúng tôi mong muốn tạo ra một ứng dụng có thể:

  1. Tải lên tệp ở định dạng JFIF (jpeg).


  2. “Bình thường hóa” ảnh gốc.


  3. Kiểm soát cường độ của “bộ chuẩn hóa”.


  4. Kết hợp LUT tùy ý từ tệp Adobe .cube vào quá trình xử lý.


  5. Quản lý cường độ tác động của CLUT.


  6. Hiển thị biểu đồ tuyến tính của hình ảnh.


  7. Hiển thị “bảng màu nén” và các màu chủ đạo của hình ảnh cũng như biểu diễn số của chúng dưới dạng bộ ba (r,g,b)


Sản phẩm cuối cùng trong quá trình xây dựng của chúng tôi sẽ giống với món đồ chơi tương tác này:

Ở đây, có thể thấy rõ việc “chuẩn hóa” đơn giản của hình ảnh ảnh hưởng tích cực như thế nào đến sự đa dạng của bảng màu cuối cùng, phân phối lại các màu chủ đạo thành một tập hợp đa dạng và hài hòa hơn.

"Bình thường hóa"

Chúng tôi sẽ tập hợp một bộ lọc từ hai bộ lọc có sẵn:

  1. IMPContrastFilter - cho phép kéo dài biểu đồ hình ảnh đến các ranh giới được chỉ định


  2. IMPAutoWBFilter - thực hiện hiệu chỉnh cân bằng trắng tự động dựa trên việc tìm kiếm màu trung bình và hiệu chỉnh các tông màu giả trong ảnh. Về cơ bản, đây là một sửa đổi nhỏ từ ý tưởng mượn từ blog của Andrey Zhuravlev .


 import IMProcessing /// Image filter public class IMPTestFilter:IMPFilter { /// We will use a contrast control filter through histogram stretching var contrastFilter:IMPContrastFilter! /// Auto white balance filter var awbFilter:IMPAutoWBFilter! /// Image Linear Histogram Analyzer var sourceAnalyzer:IMPHistogramAnalyzer! /// Solver of the histogram analyzer for calculating the lightness boundaries of the image let rangeSolver = IMPHistogramRangeSolver() public required init(context: IMPContext) { super.init(context: context) // Initialize filters in context contrastFilter = IMPContrastFilter(context: context) awbFilter = IMPAutoWBFilter(context: context) // Add filters to the stack addFilter(contrastFilter) addFilter(awbFilter) // Initialize the histogram analyzer sourceAnalyzer = IMPHistogramAnalyzer(context: self.context) // Add a light boundary search solver to the analyzer sourceAnalyzer.addSolver(rangeSolver) // Add an observing handler to the filter for // to pass the current image frame to the analyzer addSourceObserver { (source) - Void in self.sourceAnalyzer.source = source } // Add an observing handler for updating analysis calculations to the analyzer sourceAnalyzer.addUpdateObserver({ (histogram) - Void in // set the lightness boundaries in the contrast filter each time the image changes self.contrastFilter.adjustment.minimum = self.rangeSolver.minimum self.contrastFilter.adjustment.maximum = self.rangeSolver.maximum }) } }


Bộ giải bảng màu

Khung xử lý IM nổi bật so với nhiều nền tảng tương tự do cách tổ chức tính toán độc đáo của nó. Nó sử dụng một nhóm bộ lọc chuyên dụng mà về cơ bản không phải là bộ lọc xử lý.


Các đối tượng của các lớp này không sửa đổi hình ảnh trong các miền không gian và đồng nhất. Thay vào đó, họ thực hiện các phép tính và biểu diễn số liệu nhất định để phân tích trong các bộ mở rộng đặc biệt nhằm giải quyết các vấn đề cụ thể.


Chẳng hạn, một đối tượng của lớp IMPHistogramAnalyzer có thể đồng thời thêm nhiều bộ giải để tính toán màu trung bình của hình ảnh, phạm vi ánh sáng, phân chia vùng, v.v.


Chúng tôi sử dụng bộ giải để mở rộng phân tích của IMPHistogramCubeAnalyzer để tính toán bảng màu và danh sách các màu chủ đạo. Kết quả tính toán sau đó được hiển thị trong NSTableView được cập nhật.


 import IMProcessing /// Types of distribution of image color accents /// /// - palette: palette for quantizing image colors. /// calculated using the median-cut transformation scheme: /// http://www.leptonica.com/papers/mediancut.pdf /// - dominants: calculation of dominant colors of an image by searching for local maxima /// color distribution density functions: /// https://github.com/pixelogik/ColorCube /// public enum IMPPaletteType{ case palette case dominants } /// Solver of the cubic color histogram analyzer IMPHistogramCubeAnalyzer public class IMPPaletteSolver: IMPHistogramCubeSolver { /// Maximum number of palette colors for analysis public var maxColors = Int(8) /// List of found colors public var colors = [IMPColor]() /// Palette type public var type = IMPPaletteType.dominants /// Solver handler handler /// - parameter analyzer: link to the analyzer /// - parameter histogram: cubic histogram of the image /// - parameter imageSize: image size public func analizerDidUpdate(analizer: IMPHistogramCubeAnalyzer, histogram: IMPHistogramCube, imageSize: CGSize) { var p = [float3]() if type == .palette{ p = histogram.cube.palette(count: maxColors) } else if type == .dominants { p = histogram.cube.dominantColors(count: maxColors) } colors.removeAll() for c in p { colors.append(IMPColor(color: float4(rgb: c, a: 1))) } } }


Chúng tôi lắp ráp tất cả các thành phần trong View Controller

Bộ điều khiển sẽ cần bộ lọc ứng dụng chính mà chúng tôi sẽ gọi là IMPTestFilter , bộ lọc CLUT có tên IMPLutFilter, IMPHistogramView sẵn sàng sử dụng để hiển thị biểu đồ "thông thường", IMPHistogramCubeAnalyzer là bộ phân tích biểu đồ khối mà chúng tôi sẽ đính kèm bộ giải của chúng tôi, IMPPaletteSolver.


Cuối cùng, chúng ta sẽ sử dụng IMPImageView làm cửa sổ chính để hiển thị hình ảnh và IMPContext chung là lớp khóa được tất cả các hàm tạo của khung sử dụng.


 class ViewController: NSViewController { // // Processing context // let context = IMPContext() // // Window for presenting the loaded image // var imageView:IMPImageView! var pannelScrollView = NSScrollView() // // Window for displaying the image histogram // var histogramView:IMPHistogramView! // // NSTableView - views of a list of colors from the palette // var paletteView:IMPPaletteListView! // // Main filter // var filter:IMPTestFilter! // // CLUT filter from Adobe Cube files // var lutFilter:IMPLutFilter? // // Analyzer of a cubic histogram of an image in RGB space // var histograCube:IMPHistogramCubeAnalyzer! // // Our solver for finding colors // var paletteSolver = IMPPaletteSolver() var paletteTypeChooser:NSSegmentedControl! override func viewDidLoad() { super.viewDidLoad() configurePannel() // // Initialize the objects we need // filter = IMPTestFilter(context: context) histograCube = IMPHistogramCubeAnalyzer(context: context) histograCube.addSolver(paletteSolver) imageView = IMPImageView(context: context, frame: view.bounds) imageView.filter = filter imageView.backgroundColor = IMPColor(color: IMPPrefs.colors.background) // // Add another handler to monitor the original image // (another one was added in the main filter IMPTestFilter) // filter.addSourceObserver { (source) -> Void in // // to minimize calculations, the analyzer will compress the image to 1000px on the wide side // if let size = source.texture?.size { let scale = 1000/max(size.width,size.height) self.histograCube.downScaleFactor = scale.float } } // Add an observer to the filter to process the filtering results // filter.addDestinationObserver { (destination) -> Void in // pass the image to the histogram indicator self.histogramView.source = destination // pass the result to the cubic histogram analyzer self.histograCube.source = destination } // // The results of updating the analyzer calculation are displayed in the color list window // histograCube.addUpdateObserver { (histogram) -> Void in self.asyncChanges({ () -> Void in self.paletteView.colorList = self.paletteSolver.colors }) } view.addSubview(imageView) .... IMPDocument.sharedInstance.addDocumentObserver { (file, type) -> Void in if type == .Image { do{ // // Load the file and associate it with the filter source // self.imageView.source = try IMPImageProvider(context: self.imageView.context, file: file) self.asyncChanges({ () -> Void in self.zoomFit() }) } catch let error as NSError { self.asyncChanges({ () -> Void in let alert = NSAlert(error: error) alert.runModal() }) } } else if type == .LUT { do { // // Initialize the CLUT descriptor // var description = IMPImageProvider.LutDescription() // // Load CLUT // let lutProvider = try IMPImageProvider(context: self.context, cubeFile: file, description: &description) if let lut = self.lutFilter{ // // If a CLUT filter has been added, update its LUT table from the file with the received descriptor // lut.update(lutProvider, description:description) } else{ // // Create a new LUT filter // self.lutFilter = IMPLutFilter(context: self.context, lut: lutProvider, description: description) } // // Add a LUT filter, if this filter has already been added nothing happens // self.filter.addFilter(self.lutFilter!) } catch let error as NSError { self.asyncChanges({ () -> Void in let alert = NSAlert(error: error) alert.runModal() }) } } } ....


Như bạn có thể thấy, việc xử lý ảnh đang trở nên đơn giản hơn và dễ tiếp cận hơn đối với người dùng bình thường, giúp hầu như bất kỳ ai cũng có thể thành thạo quy trình này.


Toàn bộ dự án có thể được tải xuống, tập hợp và thử nghiệm từ kho dự án ImageMetalling : ImageMetalling-08 . Để lắp ráp đúng cách, thư viện lớn để làm việc với các tệp JPEG (JFIF), libjpeg-turbo , phải được cài đặt cục bộ.


Hiện tại, đây là cách triển khai hỗ trợ tốt nhất cho định dạng này.