Module: DNN::Image

Defined in:
lib/dnn/image.rb

Defined Under Namespace

Classes: ImageError, ImageReadError, ImageShapeError, ImageWriteError

Constant Summary collapse

RGB =
3
RGBA =
4

Class Method Summary collapse

Class Method Details

.from_binary(bin, height, width, channel = DNN::Image::RGB) ⇒ Object

Create an image from binary.

Parameters:

  • bin (String)

    binary data.

  • height (Integer)

    Image height.

  • width (Integer)

    Image width.

  • channel (Integer) (defaults to: DNN::Image::RGB)

    Image channel.



72
73
74
75
76
77
78
# File 'lib/dnn/image.rb', line 72

def self.from_binary(bin, height, width, channel = DNN::Image::RGB)
  expected_size = height * width * channel
  unless bin.size == expected_size
    raise ImageError, "binary size is #{bin.size}, but expected binary size is #{expected_size}"
  end
  Numo::UInt8.from_binary(bin).reshape(height, width, channel)
end

.read(file_name, channel_type = RGB) ⇒ Object

Read image from file.

Parameters:

  • file_name (String)

    File name to read.

  • channel_type (Integer) (defaults to: RGB)

    Specify channel type of image.

Raises:



20
21
22
23
24
25
26
# File 'lib/dnn/image.rb', line 20

def self.read(file_name, channel_type = RGB)
  raise ImageReadError, "#{file_name} is not found." unless File.exist?(file_name)
  bin, w, h, n = Stb.stbi_load(file_name, channel_type)
  raise ImageReadError, "#{file_name} load failed." if bin == ""
  img = Numo::UInt8.from_binary(bin)
  img.reshape(h, w, channel_type)
end

.resize(img, out_height, out_width) ⇒ Object

Resize the image.

Parameters:

  • img (Numo::UInt8)

    Image to resize.

  • out_height (Integer)

    Image height to resize.

  • out_width (Integer)

    Image width to resize.



84
85
86
87
88
89
90
# File 'lib/dnn/image.rb', line 84

def self.resize(img, out_height, out_width)
  img_check(img)
  in_height, in_width, ch = *img.shape
  out_bin, res = Stb.stbir_resize_uint8(img.to_binary, in_width, in_height, 0, out_width, out_height, 0, ch)
  img2 = Numo::UInt8.from_binary(out_bin).reshape(out_height, out_width, ch)
  img2
end

.to_gray_scale(img) ⇒ Object

Image convert to gray scale.

Parameters:

  • img (Numo::UInt8)

    Image to gray scale.



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/dnn/image.rb', line 105

def self.to_gray_scale(img)
  img_check(img)
  if img.shape[2] == RGB
    x = Numo::SFloat.cast(img)
    x = x.mean(axis: 2, keepdims: true)
  elsif img.shape[2] == RGBA
    x = Numo::SFloat.cast(img[true, true, 0..2])
    x = x.mean(axis: 2, keepdims: true).concatenate(img[true, true, 3..3], axis: 2)
  end
  Numo::UInt8.cast(x)
end

.to_rgb(img) ⇒ Object

Image convert image channel to RGB.

Parameters:

  • img (Numo::UInt8)

    Image to RGB.



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/dnn/image.rb', line 119

def self.to_rgb(img)
  img_check(img)
  case img.shape[2]
  when 1
    return img.concatenate(img, axis: 2).concatenate(img, axis: 2)
  when 2
    img = img[true, true, 0...1]
    return img.concatenate(img, axis: 2).concatenate(img, axis: 2)
  when 4
    return img[true, true, 0...3].clone
  end
  img
end

.to_rgba(img) ⇒ Object

Image convert image channel to RGBA.

Parameters:

  • img (Numo::UInt8)

    Image to RGBA.



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/dnn/image.rb', line 135

def self.to_rgba(img)
  img_check(img)
  case img.shape[2]
  when 1
    alpha = Numo::UInt8.new(*img.shape[0..1], 1).fill(255)
    return img.concatenate(img, axis: 2).concatenate(img, axis: 2).concatenate(alpha, axis: 2)
  when 2
    alpha = img[true, true, 1...2]
    img = img[true, true, 0...1]
    return img.concatenate(img, axis: 2).concatenate(img, axis: 2).concatenate(alpha, axis: 2)
  when 3
    alpha = Numo::UInt8.new(*img.shape[0..1], 1).fill(255)
    return img.concatenate(alpha, axis: 2)
  end
  img
end

.trim(img, y, x, height, width) ⇒ Object

Trimming the image.

Parameters:

  • img (Numo::UInt8)

    Image to resize.

  • y (Integer)

    The begin y coordinate of the image to trimming.

  • x (Integer)

    The begin x coordinate of the image to trimming.

  • height (Integer)

    Image height to trimming.

  • width (Integer)

    Image height to trimming.



98
99
100
101
# File 'lib/dnn/image.rb', line 98

def self.trim(img, y, x, height, width)
  img_check(img)
  img[y...(y + height), x...(x + width), true].clone
end

.write(file_name, img, quality: 100) ⇒ Object

Write image to file.

Parameters:

  • file_name (String)

    File name to write.

  • img (Numo::UInt8)

    Image to write.

  • quality (Integer) (defaults to: 100)

    Image quality when jpeg write.

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dnn/image.rb', line 32

def self.write(file_name, img, quality: 100)
  img_check(img)
  match_data = file_name.match(%r`(.*)/.+$`)
  if match_data
    dir_name = match_data[1]
    Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
  end
  h, w, ch = img.shape
  match_data = file_name.match(/\.(\w+)$/i)
  if match_data
    ext = match_data[1]
  else
    raise ImageWriteError, "File name has not extension."
  end
  case ext
  when "png"
    stride_in_bytes = w * ch
    res = Stb.stbi_write_png(file_name, w, h, ch, img.to_binary, stride_in_bytes)
  when "bmp"
    res = Stb.stbi_write_bmp(file_name, w, h, ch, img.to_binary)
  when "jpg", "jpeg"
    raise TypeError, "quality:#{quality.class} is not an instance of Integer class." unless quality.is_a?(Integer)
    raise ArgumentError, "quality should be between 1 and 100." unless quality.between?(1, 100)
    res = Stb.stbi_write_jpg(file_name, w, h, ch, img.to_binary, quality)
  when "hdr"
    float_img = Numo::SFloat.cast(img) / 255
    res = Stb.stbi_write_hdr(file_name, w, h, ch, float_img.to_binary)
  when "tga"
    res = Stb.stbi_write_tga(file_name, w, h, ch, img.to_binary)
  else
    raise ImageWriteError, "Extension '#{ext}' is not support."
  end
  raise ImageWriteError, "Image write failed." if res == 0
end