Skip to content

Commit 7cf68cc

Browse files
committed
feat: duotone, linocut, posterize, solarize
1 parent ffa919d commit 7cf68cc

File tree

8 files changed

+175
-79
lines changed

8 files changed

+175
-79
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: aznyan
33
Title: Image Filters with 'OpenCV'
4-
Version: 26.01.07
4+
Version: 26.02.05
55
Authors@R: c(
66
person("Akiru", "Kato", , "paithiov909@gmail.com", role = c("aut", "cre")),
77
person("Jeroen", "Ooms", role = "cph")

NAMESPACE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,29 @@ export(contrast)
3636
export(convolve)
3737
export(detail_enchance)
3838
export(diffusion_filter)
39+
export(duotone)
3940
export(fade_with)
4041
export(fill_with)
4142
export(gaussian_blur)
4243
export(grayscale)
4344
export(hist_eq)
4445
export(hls2rgb)
4546
export(hue_rotate)
47+
export(invert)
4648
export(kernel_cone)
4749
export(kernel_disc)
4850
export(kernel_emboss)
4951
export(kernel_motion)
5052
export(kernel_ring)
5153
export(kuwahara_filter)
5254
export(laplacian_filter)
55+
export(linocut)
5356
export(mean_shift)
5457
export(median_blur)
5558
export(morphology)
5659
export(oilpaint)
5760
export(pencil_sketch)
61+
export(posterize)
5862
export(premul)
5963
export(preserve_edge)
6064
export(read_still)
@@ -66,6 +70,7 @@ export(saturate)
6670
export(sepia)
6771
export(set_matte)
6872
export(sobel_filter)
73+
export(solarize)
6974
export(stylize)
7075
export(swap_channels)
7176
export(thres)

R/blend.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ clamp <- function(x, min, max) {
1818
pmin(pmax(x, min), max)
1919
}
2020

21+
#' Lerp
22+
#'
23+
#' @param x,y numerics
24+
#' @param mask numeric scalar
25+
#' @returns numerics
26+
#' @noRd
27+
mix <- function(x, y, mask) {
28+
mask <- clamp(mask, 0, 1)
29+
x * mask + y * (1 - mask)
30+
}
31+
32+
#' Step
33+
#'
34+
#' @param x,y numerics
35+
#' @param mask numeric scalar
36+
#' @returns numerics
37+
#' @noRd
38+
step <- function(x, mask) {
39+
(x > mask) * 1
40+
}
41+
2142
#' Alpha blending
2243
#'
2344
#' @param x1,x2 Alpha values.

R/color-manip.R

Lines changed: 102 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,42 @@ NULL
88

99
#' @rdname rgb-hls
1010
#' @export
11-
rgb2hls <- function(x) azny_rgb_to_hls(x)
11+
rgb2hls <- function(x) azny_rgb_to_hls(floor(x))
1212

1313
#' @rdname rgb-hls
1414
#' @export
15-
hls2rgb <- function(x) azny_hls_to_rgb(x)
15+
hls2rgb <- function(x) azny_hls_to_rgb(floor(x))
16+
17+
#' Create a native raster filled with a color
18+
#'
19+
#' @param width,height A positive integer scalar.
20+
#' @param color Color name or hex code.
21+
#' @returns A `nativeRaster` object.
22+
#' @export
23+
fill_with <- function(width, height, color) {
24+
packed_int <-
25+
grDevices::col2rgb(color[1], alpha = TRUE) |>
26+
rlang::as_function(
27+
~ {
28+
x <- as.double(.)
29+
azny_pack_integers(x[1:3], x[4], 1, 1)
30+
}
31+
)()
32+
out <- rep_len(packed_int, width * height)
33+
dim(out) <- c(height, width)
34+
as_nr(out)
35+
}
1636

1737
#' Color manipulation
1838
#'
1939
#' @param nr A `nativeRaster` object.
2040
#' @param intensity A numeric scalar.
21-
#' @param depth An integer scalar.
22-
#' @param color A character string; the color to be set.
23-
#' @param alpha A numeric scalar in range `[0, 1]`.
24-
#' The alpha value to be reset for transparency.
41+
#' @param depth,shades A positive integer scalar.
42+
#' @param gamma A numeric scalar. The gamma exponent.
2543
#' @param rad A numeric scalar. The rotation angle in radians.
44+
#' @param color,color_a,color_b,ink,paper A character string;
45+
#' color name or hex code.
46+
#' @param alpha,threshold A numeric scalar in range `[0, 1]`.
2647
#' @param max An integer scalar. The maximum value of the color code.
2748
#' @returns A `nativeRaster` object.
2849
#' @rdname color-manip
@@ -31,33 +52,41 @@ NULL
3152

3253
#' @rdname color-manip
3354
#' @export
34-
unpremul <- function(nr, max = 255L) {
55+
brighten <- function(nr, intensity) {
3556
sz <- dim(nr)
3657
ret <- nr_to_rgba(nr, "nr")
37-
rgb <- ret[1:3, ] / (ret[4, ] / max)
58+
rgb <- clamp(ret[1:3, ] * (1 + intensity), 0, 255)
3859
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
3960
}
4061

4162
#' @rdname color-manip
4263
#' @export
43-
set_matte <- function(nr, color = "green") {
44-
rgb_int <-
45-
grDevices::col2rgb(color[1], alpha = FALSE)
64+
contrast <- function(nr, intensity) {
4665
sz <- dim(nr)
4766
ret <- nr_to_rgba(nr, "nr")
48-
ret[1, ][ret[4, ] != 255] <- rgb_int[1, ] * 1
49-
ret[2, ][ret[4, ] != 255] <- rgb_int[2, ] * 1
50-
ret[3, ][ret[4, ] != 255] <- rgb_int[3, ] * 1
51-
as_nr(azny_pack_integers(ret[1:3, ], ret[4, ], sz[1], sz[2]))
67+
rgb <- clamp((ret[1:3, ] / 255 - 0.5) * (1 + intensity) + 0.5, 0, 1) * 255
68+
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
5269
}
5370

5471
#' @rdname color-manip
5572
#' @export
56-
reset_alpha <- function(nr, alpha = 1) {
73+
duotone <- function(nr, color_a = "yellow", color_b = "navy", gamma = 2.2) {
5774
sz <- dim(nr)
75+
color_a <- fill_with(sz[1], sz[2], color_a) |> nr_to_rgba("color_a")
76+
color_b <- fill_with(sz[1], sz[2], color_b) |> nr_to_rgba("color_b")
5877
ret <- nr_to_rgba(nr, "nr")
59-
ret[4, ] <- clamp(alpha * 255, 0, 255)
60-
as_nr(azny_pack_integers(ret[1:3, ], ret[4, ], sz[1], sz[2]))
78+
luminance <- clamp(gray(ret[1:3, ])^(1 / gamma), 0, 1)
79+
rgb <- mix(color_a[1:3, ], color_b[1:3, ], luminance)
80+
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
81+
}
82+
83+
#' @rdname color-manip
84+
#' @export
85+
grayscale <- function(nr) {
86+
sz <- dim(nr)
87+
ret <- nr_to_rgba(nr, "nr")
88+
rgb <- t(colSums(ret[1:3, ]) / 3) %x% c(1, 1, 1)
89+
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
6190
}
6291

6392
#' @rdname color-manip
@@ -92,22 +121,43 @@ hue_rotate <- function(nr, rad) {
92121

93122
#' @rdname color-manip
94123
#' @export
95-
contrast <- function(nr, intensity) {
124+
invert <- function(nr) {
96125
sz <- dim(nr)
97126
ret <- nr_to_rgba(nr, "nr")
98-
rgb <- clamp((ret[1:3, ] / 255 - 0.5) * (1 + intensity) + 0.5, 0, 1) * 255
127+
rgb <- 255 - ret[1:3, ]
99128
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
100129
}
101130

102131
#' @rdname color-manip
103132
#' @export
104-
brighten <- function(nr, intensity) {
133+
linocut <- function(nr, ink = "navy", paper = "snow", threshold = 0.4) {
105134
sz <- dim(nr)
135+
ink <- fill_with(sz[1], sz[2], ink) |> nr_to_rgba("ink")
136+
paper <- fill_with(sz[1], sz[2], paper) |> nr_to_rgba("paper")
106137
ret <- nr_to_rgba(nr, "nr")
107-
rgb <- clamp(ret[1:3, ] * (1 + intensity), 0, 255)
138+
luminance <- step(gray(ret[1:3, ]), threshold)
139+
rgb <- mix(paper[1:3, ], ink[1:3, ], luminance)
108140
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
109141
}
110142

143+
#' @rdname color-manip
144+
#' @export
145+
posterize <- function(nr, shades = 4) {
146+
sz <- dim(nr)
147+
ret <- nr_to_rgba(nr, "nr")
148+
rgb <- floor(ret[1:3, ] / 255 * shades) / as.integer(shades - 1)
149+
as_nr(azny_pack_integers(rgb * 255, ret[4, ] * 1, sz[1], sz[2]))
150+
}
151+
152+
#' @rdname color-manip
153+
#' @export
154+
reset_alpha <- function(nr, alpha = 1) {
155+
sz <- dim(nr)
156+
ret <- nr_to_rgba(nr, "nr")
157+
ret[4, ] <- clamp(alpha * 255, 0, 255)
158+
as_nr(azny_pack_integers(ret[1:3, ], ret[4, ], sz[1], sz[2]))
159+
}
160+
111161
#' @rdname color-manip
112162
#' @export
113163
saturate <- function(nr, intensity) {
@@ -123,16 +173,7 @@ saturate <- function(nr, intensity) {
123173

124174
#' @rdname color-manip
125175
#' @export
126-
grayscale <- function(nr) {
127-
sz <- dim(nr)
128-
ret <- nr_to_rgba(nr, "nr")
129-
rgb <- t(colSums(ret[1:3, ]) / 3) %x% c(1, 1, 1)
130-
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
131-
}
132-
133-
#' @rdname color-manip
134-
#' @export
135-
sepia <- function(nr, intensity = 1, depth = 20) {
176+
sepia <- function(nr, intensity, depth = 20) {
136177
sz <- dim(nr)
137178
ret <- nr_to_rgba(nr, "nr")
138179
rgb <- rbind(
@@ -145,22 +186,34 @@ sepia <- function(nr, intensity = 1, depth = 20) {
145186
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
146187
}
147188

148-
#' Create a native raster filled with a color
149-
#'
150-
#' @param width,height A positive integer scalar.
151-
#' @param color Color name or hex code.
152-
#' @returns A `nativeRaster` object.
189+
#' @rdname color-manip
153190
#' @export
154-
fill_with <- function(width, height, color) {
155-
packed_int <-
156-
grDevices::col2rgb(color[1], alpha = TRUE) |>
157-
rlang::as_function(
158-
~ {
159-
x <- as.double(.)
160-
azny_pack_integers(x[1:3], x[4], 1, 1)
161-
}
162-
)()
163-
out <- rep(packed_int, width * height)
164-
dim(out) <- c(height, width)
165-
as_nr(out)
191+
set_matte <- function(nr, color = "green") {
192+
rgb_int <-
193+
grDevices::col2rgb(color[1], alpha = FALSE)
194+
sz <- dim(nr)
195+
ret <- nr_to_rgba(nr, "nr")
196+
ret[1, ][ret[4, ] != 255] <- rgb_int[1, ] * 1
197+
ret[2, ][ret[4, ] != 255] <- rgb_int[2, ] * 1
198+
ret[3, ][ret[4, ] != 255] <- rgb_int[3, ] * 1
199+
as_nr(azny_pack_integers(ret[1:3, ], ret[4, ], sz[1], sz[2]))
200+
}
201+
202+
#' @rdname color-manip
203+
#' @export
204+
solarize <- function(nr, threshold = 0.5) {
205+
sz <- dim(nr)
206+
ret <- nr_to_rgba(nr, "nr")
207+
intensity <- colSums(ret[1:3, ] / 255) / 3
208+
rgb <- ifelse(intensity > threshold, 255 - ret[1:3, ], ret[1:3, ])
209+
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
210+
}
211+
212+
#' @rdname color-manip
213+
#' @export
214+
unpremul <- function(nr, max = 255L) {
215+
sz <- dim(nr)
216+
ret <- nr_to_rgba(nr, "nr")
217+
rgb <- ret[1:3, ] / (ret[4, ] / max)
218+
as_nr(azny_pack_integers(rgb, ret[4, ] * 1, sz[1], sz[2]))
166219
}

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ their first argument and return a `nativeRaster` after applying the
2222
effect. All these functions return a new `nativeRaster` and do not
2323
modify the input object in place.
2424

25-
A `nativeRaster` is a built-in datatype in R that stores image data as an
26-
integer matrix. There are several common ways to obtain a `nativeRaster`
27-
object:
25+
A `nativeRaster` is a built-in datatype in R that stores image data as
26+
an integer matrix. There are several common ways to obtain a
27+
`nativeRaster` object:
2828

2929
- Generate or manipulate a `nativeRaster` using
3030
[nara](https://github.com/coolbutuseless/nara)

man/color-manip.Rd

Lines changed: 37 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)