0

[Android] Image Color Change With ColorMatrix

1. Introduction

Đã bao giờ bạn tự hỏi liệu để đổi màu sắc của một bức ảnh có phức tạp không ? Hay bộ filter màu của các app chỉnh sửa làm thế nào mà trông xịn vậy ? Trong bài viết này, mình sẽ hướng dẫn chi các bạn làm thế nào để xử lý bài toán trên với ColorMatrix.

2. ColorMatrix

Để minh họa, mình sẽ sử dụng hình ảnh hoa hồng bên dưới nhé :

2.1. ColorMatrix Mathematically

ColorMatrix là một lớp dữ liệu chứa một mảng [4x5] các giá trị bao gồm 4 hàng x 5 cột. Về mặt toán học, nó được biểu diễn như sau :

[ a, b, c, d, e,
  f, g, h, i, j,
  k, l, m, n, o,
  p, q, r, s, t ]

Sau đó, bộ màu [R' G' B' A'] được áp dụng cho bức ảnh là một phép toán dựa trên màu gốc [RGBA] như sau :

R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;

Nhìn trông có vẻ phức tạp, giờ mình sẽ giải thích nó một cách đơn giản qua các ví dụ.

Trước khi làm điều đó, cùng xem convert 1 bức ảnh sang gray bằng code :

val matrix = floatArray(
    1f, 1f, 1f, 0f, 0f,
    1f, 1f, 1f, 0f, 0f,
    1f, 1f, 1f, 0f, 0f,
    0f, 0f, 0f, 1f, 0f)
image.colorFilter = ColorMatrixColorFilter(matrix)

2.2. Original Color

Nếu bạn muốn có màu gốc như hình ảnh, matrix sẽ như sau :

[ 1, 0, 0, 0, 0,
  0, 1, 0, 0, 0,
  0, 0, 1, 0, 0,
  0, 0, 0, 1, 0 ]

Bạn sẽ nhận ra điều này, màu mới sẽ có hệ số như sau :

R' = 1*R
G' = 1*G
B' = 1*B
A' = 1*A

3. Colorized It

Để tô màu nó thành một màu củ thể, ta chỉ cần tập trung vào hàng cụ thể cho màu mà chúng ta muốn thay đổi.

3.1 Red

Nếu bạn muốn đổi màu bức ảnh sang màu đỏ hoặc không màu, hãy tập trung vào dòng đầu tiên.

[ 1, 1, 1, 0, 0,
  0, 0, 0, 0, 0,
  0, 0, 0, 0, 0,
  0, 0, 0, 1, 0 ]

Công thức như sau :

R' = 1*R + 1*G + 1*B
G' = 0
B' = 0
A' = 1*A (giữ nguyên dộ mờ)

Điều này có nghĩ bất cứ màu đổ đậm, xanh lá cây, hoặc xanh dương sẽ trở thành màu đỏ đậm. Còn những phần yếu hơn sẽ có màu đỏ tối hơn hoặc đen.

3.2 Green

Tương tự, đối với màu xanh lá cây. Ta có thể làm tương tự bằng cách focus vào hàng thứ 2.

[ 0, 0, 0, 0, 0,
  1, 1, 1, 0, 0,
  0, 0, 0, 0, 0,
  0, 0, 0, 1, 0 ]

Kết quả :

3.3 Blue

Đối với màu xanh dương, Focus vào hàng thứ ba :

[ 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0,
  1, 1, 1, 0, 0,
  0, 0, 0, 1, 0 ]

Kết quả :

3.4 Gray Scale It

Màu xám là màu thỏa màn R,G,B có cùng 1 giá trị. Để đồng đều màu xám, sử dụng công thức dưới đây ( Chú ý : Mình sử dụng 0.33 thay vì 1 để đảm bảo nó không sáng quá, giá trị càng lớn, hình ảnh sẽ càng sáng (hoặc trắng ) hơn.

[ 0.33, 0.33, 0.33, 0, 0,
  0.33, 0.33, 0.33, 0, 0,
  0.33, 0.33, 0.33, 0, 0,
  0, 0, 0, 1, 0 ]

Kết quả sẽ như dưới đây trong đó R' = G' = B'

R' = 0.33*R + 0.33*G + 0.33*B
G' = 0.33*R + 0.33*G + 0.33*B
B' = 0.33*R + 0.33*G + 0.33*B
A' = 1*A ( giữ nguyên độ mờ)

3.5 Inverting the Color

Giống như phim ảnh ngày xưa, nếu ta muốn đảo ngược màu của hình ảnh. Ta cần tạo 1 số với giá trị 255 - màu gốc.

[ -1, 0, 0, 0, 255,
  0, -1, 0, 0, 255,
  0, 0, -1, 0, 255,
  0, 0, 0, 1, 0 ]

Khi đó, bộ màu mới sẽ như sau :

R' = -1*R + 255 = 255 -1*R
G' = -1*G + 255 = 255 -1*G
B' = -1*B + 255 = 255 -1*B
A' = 1*A

4. ColorMatrix Data Class

Nếu thao tác thủ công ma trận gây rắc rối cho bạn, bạn có thể sử dụng lớp ColorMatrix. Khởi tạo một ma trận gốc như sau :

val colorMatrix = ColorMatrix()

Ma trận gốc thủ công sẽ như sau :

[ 1, 0, 0, 0, 0,
  0, 1, 0, 0, 0,
  0, 0, 1, 0, 0,
  0, 0, 0, 1, 0 ]

Chuyển đổi ma trận sang code :

val matrix = floatArray(
  1f, 0f, 0f, 0f, 0f,
  0f, 1f, 0f, 0f, 0f,
  0f, 0f, 1f, 0f, 0f,
  0f, 0f, 0f, 1f, 0f)

Cuối cùng, áp dụng filter cho ảnh bằng dòng lệnh :

image.colorFilter = ColorMatrixColorFilter(matrix)

OK, giờ cùng tìm hiểu 1 số thuật toán chuyển đổi nữa nhé.

4.1 Scaling

Scale đơn giản là làm sáng từng vùng màu sao cho phù hợp.

Thông thường, nó sẽ được set khoảng 0-1 ( từ không màu -> màu gốc ). Tuy nhiên, nó cũng được set lớn hơn 1 để làm sáng màu cụ thể.

matrix.setScale(redScale, greenScale, blueScale, alphaScale)

4.2 Saturation

Saturation ( bão hòa ) là sự chuyển đổi màu từ màu xám chưa bão hòa sang màu gốc và cao hơn. Nó trông giống scaling nhưng thiên về màu sắc hơn ( ko có khả năng tạo hiệu ứng làm trắng như scaling )

matrix.setSaturation(saturationValue)

4.3 Rotating

Tương tự như scaling nhưng áp dụng cho 1 màu cụ thể.

matrix.setRotate(colorInt, degree)

colorInt thuộc các giá trị : 0 - đỏ, 1 = xanh lá, 2 = xanh da trời. Và degree trong khoảng 0 -> 360.

5. Conclusion

Về cơ bản, có rất nhiều cách để thao tác với màu sắc. Happy coding ^^

6. Reference


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí