How to resolve the algorithm Bitmap/Flood fill step by step in the Ruby programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Bitmap/Flood fill step by step in the Ruby programming language

Table of Contents

Problem Statement

A flood fill is a way of filling an area using color banks to define the contained area or a target color which "determines" the area (the valley that can be flooded; Wikipedia uses the term target color). It works almost like a water flooding from a point towards the banks (or: inside the valley): if there's a hole in the banks, the flood is not contained and all the image (or all the "connected valleys") get filled. To accomplish the task, you need to implement just one of the possible algorithms (examples are on Wikipedia). Variations on the theme are allowed (e.g. adding a tolerance parameter or argument for color-matching of the banks or target color). Testing: the basic algorithm is not suitable for truecolor images; a possible test image is the one shown on the right box; you can try to fill the white area, or the black inner circle.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Bitmap/Flood fill step by step in the Ruby programming language

The provided Ruby code implements a flood fill algorithm for a raster graphics image. Here's a detailed explanation:

Raster Graphics:

The RasterGraphics module, which is required at the beginning of the script, provides functionality for working with raster graphics images.

RGBColour Class:

The RGBColour class defines a simple color object with a == method to compare the color values of two instances.

Pixmap Class:

The Pixmap class represents a raster graphics image. It provides methods for drawing shapes, including lines and circles, and for performing image transformations.

Flood Fill Algorithm Implementation:

The flood_fill method in the Pixmap class implements the flood fill algorithm. It takes two arguments:

  1. pixel: The pixel from which to start the fill.
  2. new_colour: The color to fill the connected region with.

The algorithm works as follows:

  1. It initializes a queue of pixels with the starting pixel.
  2. It iterates over the queue until it's empty.
  3. For each pixel in the queue, it checks if it has the same color as the pixel from which the fill started.
  4. If the pixel has the same color, it draws a horizontal line from the westernmost border to the easternmost border of the connected region with the new color.
  5. It then adds the pixels to the north and south of the current pixel to the queue if they have the same color.

Neighboring Pixels:

The neighbour method returns the pixel adjacent to the given pixel in a specified direction. The directions supported are north, south, east, and west.

Boundary Detection:

The find_border method finds the border of a connected region of pixels with a given color in a specified direction. It works by moving in the given direction until it encounters a pixel with a different color.

Usage of the Flood Fill Algorithm:

The script contains an example of using the flood fill algorithm on a bitmap image. It draws two circles on the image and then fills the area between the circles with a blue color. The filled image is then saved as a PNG file.

Processing Sketch Implementation:

The included Processing sketch provides a graphical user interface for interacting with the flood fill algorithm. It allows the user to load an image, click on it, and fill the connected region of pixels with a specified color.

Summary:

The provided Ruby code and Processing sketch demonstrate the implementation and use of a flood fill algorithm for raster graphics images. It allows you to fill connected regions of pixels with a specified color, and it's commonly used in image editing and graphics applications.

Source code in the ruby programming language

# frozen_string_literal: true

require_relative 'raster_graphics'

class RGBColour
  def ==(other)
    values == other.values
  end
end

class Pixmap
  def flood_fill(pixel, new_colour)
    current_colour = self[pixel.x, pixel.y]
    queue = Queue.new
    queue.enq(pixel)
    until queue.empty?
      p = queue.pop
      next unless self[p.x, p.y] == current_colour

      west = find_border(p, current_colour, :west)
      east = find_border(p, current_colour, :east)
      draw_line(west, east, new_colour)
      q = west
      while q.x <= east.x
        %i[north south].each do |direction|
          n = neighbour(q, direction)
          queue.enq(n) if self[n.x, n.y] == current_colour
        end
        q = neighbour(q, :east)
      end
    end
  end

  def neighbour(pixel, direction)
    case direction
    when :north then Pixel[pixel.x, pixel.y - 1]
    when :south then Pixel[pixel.x, pixel.y + 1]
    when :east  then Pixel[pixel.x + 1, pixel.y]
    when :west  then Pixel[pixel.x - 1, pixel.y]
    end
  end

  def find_border(pixel, colour, direction)
    nextp = neighbour(pixel, direction)
    while self[nextp.x, nextp.y] == colour
      pixel = nextp
      nextp = neighbour(pixel, direction)
    end
    pixel
  end
end

bitmap = Pixmap.new(300, 300)
bitmap.draw_circle(Pixel[149, 149], 120, RGBColour::BLACK)
bitmap.draw_circle(Pixel[200, 100], 40, RGBColour::BLACK)
bitmap.flood_fill(Pixel[140, 160], RGBColour::BLUE)
bitmap.save_as_png('flood_fill.png')


# holder for pixel coords
Pixel = Struct.new(:x, :y)

attr_reader :img, :fill_color, :queue, :value

def setup
  sketch_title 'Flood Fill'
  @img = load_image(data_path('image.png'))
  @fill_color = color(250, 0, 0)
end

def draw
  image(img, 0, 0, width, height)
  no_loop
end

def mouse_clicked
  img.load_pixels
  flood(mouse_x, mouse_y)
  img.update_pixels
  redraw
end

def flood(x, y)
  @queue = Queue.new
  queue.enq(Pixel.new(x, y))
  until queue.empty?
    pix = queue.pop
    next unless check(pix, color(255))

    queue.enq(Pixel.new(pix.x, pix.y - 1))
    queue.enq(Pixel.new(pix.x, pix.y + 1))
    queue.enq(Pixel.new(pix.x - 1, pix.y))
    queue.enq(Pixel.new(pix.x + 1, pix.y))
  end
end

def check(pix, target_color)
  unless (1...width).include?(pix.x) && (1...height).include?(pix.y)
    return false
  end

  value = img.pixels[pix.x + (pix.y * img.width)]
  return false if target_color != value

  img.pixels[pix.x + (pix.y * img.width)] = fill_color
  true
end

def settings
  size(256, 256)
end


  

You may also check:How to resolve the algorithm Loops/Nested step by step in the Forth programming language
You may also check:How to resolve the algorithm Window creation step by step in the Pascal programming language
You may also check:How to resolve the algorithm Generate Chess960 starting position step by step in the Seed7 programming language
You may also check:How to resolve the algorithm Monty Hall problem step by step in the Kotlin programming language
You may also check:How to resolve the algorithm Calendar - for REAL programmers step by step in the Elena programming language