Packages
image
0.67.0
0.72.0
0.71.0
0.70.0
0.69.0
0.68.0
0.67.0
0.67.0-dev
retired
0.66.0
0.65.0
0.64.0
0.63.0
0.62.1
0.62.0
0.61.1
0.61.0
0.60.0
0.59.3
0.59.2
0.59.1
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.2
0.55.1
retired
0.55.0
0.54.4
0.54.3
0.54.2
0.54.1
0.54.0
0.53.0
0.52.3
0.52.2
0.52.1
0.52.0
retired
0.51.0
0.50.0
0.49.0
0.48.1
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.2
0.43.1
0.43.0
0.42.0
0.41.0
0.40.0
0.39.3
0.39.2
0.39.1
0.39.0
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.0
0.36.2
0.36.1
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.0
0.25.1
0.25.0
0.24.1
0.24.0
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
retired
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.4
0.14.2
0.14.1
0.14.0
retired
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.10.0-rc.0
retired
0.9.0
retired
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
An approachable image processing library primarily based upon Vix and libvips that is NIF-based, fast, multi-threaded, pipelined and has a low memory footprint.
Current section
Files
Jump to
Current section
Files
lib/image/scholar.ex
if match?({:module, _module}, Code.ensure_compiled(Scholar.Cluster.KMeans)) and
match?({:module, _module}, Code.ensure_compiled(Nx)) do
defmodule Image.Scholar do
import Nx
alias Vix.Vips.Image, as: Vimage
@square_256 256 ** 2
@bands 3
def unique_colors(%Vimage{} = image) do
with {:ok, tensor} <- Image.to_nx(image) do
bands = Image.bands(image)
colors_base256 =
tensor
|> encode_colors(bands)
|> Nx.flatten()
|> Nx.sort()
diff =
diff(colors_base256)
unique_indices_selector =
Nx.concatenate([Nx.tensor([1]), Nx.not_equal(diff, 0)])
marked_unique_indices =
Nx.select(unique_indices_selector, Nx.iota(colors_base256.shape), -1)
repeated_count =
Nx.to_number(Nx.sum(Nx.logical_not(unique_indices_selector)))
unique_indices =
marked_unique_indices
|> Nx.sort()
|> Nx.slice_along_axis(repeated_count, Nx.size(marked_unique_indices) - repeated_count,
axis: 0
)
unique_colors =
Nx.take(colors_base256, unique_indices)
|> decode_colors(bands)
count = div(Nx.size(colors_base256), @bands)
max = Nx.to_number(Nx.reduce_max(unique_indices))
color_count = Nx.concatenate([diff(unique_indices), Nx.tensor([count - max])])
{:ok, {color_count, unique_colors}}
end
end
def k_means(%Vimage{} = image, options \\ []) do
with {:ok, {_count, colors}} <- unique_colors(image) do
Scholar.Cluster.KMeans.fit(colors, options)
end
end
defp encode_colors(colors, 3) do
colors
|> Nx.multiply(Nx.tensor([[1, 256, @square_256]]))
|> Nx.sum(axes: [2])
end
defp encode_colors(colors, 4) do
colors
|> Nx.multiply(Nx.tensor([[1, 256, @square_256, 256 * @square_256]]))
|> Nx.sum(axes: [2])
end
defp decode_colors(encoded_colors, 3) do
b = Nx.quotient(encoded_colors, @square_256)
rem = Nx.remainder(encoded_colors, @square_256)
g = Nx.quotient(rem, 256)
r = Nx.remainder(rem, 256)
Nx.stack([r, g, b], axis: 1)
end
defp decode_colors(encoded_colors, 4) do
a = Nx.quotient(encoded_colors, 256 * @square_256)
rem = Nx.remainder(encoded_colors, 256 * @square_256)
b = Nx.quotient(rem, @square_256)
rem = Nx.remainder(rem, @square_256)
g = Nx.quotient(rem, 256)
r = Nx.remainder(rem, 256)
Nx.stack([r, g, b, a], axis: 1)
end
end
end