1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

色の濃淡のみでASCII ARTを描画してみる

Posted at

今回は、画像から色の濃淡のみでASCII ARTを描画します。

必要なものの宣言

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>

using namespace cv;
using namespace std;

明るさに応じた文字を返す関数を作る

char mapGrayscaleToAscii(int grayscale_value) {
  const string ascii_chars = " .:-=+*#%@";

  // Map 0-255 grayscale value to character index
  int index = (grayscale_value * (ascii_chars.size() - 1)) / 255;

  return ascii_chars[index];
}

受け取った画像をもとにASCII ARTに変換

string imageToAscii(Mat &image, int output_width) {
  // 画像が白黒でなければ変換する
  Mat grayscale;
  if (image.channels() == 3) {
    cvtColor(image, grayscale, COLOR_BGR2GRAY);
  } else {
    grayscale = image.clone();
  }

  // 大きさを計算する
  float aspect_ratio = (float)grayscale.rows / (float)grayscale.cols;
  int output_height = (int)(output_width * aspect_ratio *
                            0.5); // 0.5 because chars are taller than wide

  // 画像を出力したい大きさに合わせてスケールし直す
  Mat resized;
  resize(grayscale, resized, Size(output_width, output_height), 0, 0,
         INTER_AREA);

  // 各ピクセルをアスキーアートに変換する
  string ascii_art;
  for (int y = 0; y < resized.rows; y++) {
    for (int x = 0; x < resized.cols; x++) {
      int pixel_value = (int)resized.at<uchar>(y, x);
      ascii_art += mapGrayscaleToAscii(pixel_value);
    }
    ascii_art += '\n';
  }

  return ascii_art;
}

引数を受け取って処理する

int main(int argc, char **argv) {
  // Check command line arguments
  if (argc < 2) {
    cout << "Usage: " << argv[0] << " <image_path> [output_width]" << endl;
    cout << "  image_path: Path to the input image" << endl;
    cout << "  output_width: Width of ASCII output in characters (default: 100)"
         << endl;
    return -1;
  }

  string image_path = argv[1];
  int output_width = 100; // Default width

  if (argc >= 3) {
    output_width = stoi(argv[2]);
  }

  // Load the image
  Mat image = imread(image_path, IMREAD_COLOR);

  if (image.empty()) {
    cerr << "Error: Could not open or find the image: " << image_path << endl;
    return -1;
  }

  // Convert to ASCII
  string ascii_art = imageToAscii(image, output_width);

  // Output the result
  cout << ascii_art << endl;

  return 0;
}

最後に

コード全体

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>

using namespace cv;
using namespace std;

/**
 * Maps a grayscale value (0-255) to an ASCII character
 *
 * This function determines which ASCII character represents a given brightness
 * level. Since we assume white characters on black background:
 * - Dark pixels (low values) should map to sparse/light characters
 * - Bright pixels (high values) should map to dense/heavy characters
 *
 * @param grayscale_value: Pixel brightness (0 = black, 255 = white)
 * @return: ASCII character representing that brightness
 */
char mapGrayscaleToAscii(int grayscale_value) {
  // Simple character set from light to dark (for white text on black
  // background) Ordered by visual density: space is lightest, @ is darkest
  const string ascii_chars = " .:-=+*#%@";

  // Map 0-255 grayscale value to character index
  int index = (grayscale_value * (ascii_chars.size() - 1)) / 255;

  return ascii_chars[index];
}

/**
 * Converts an image to ASCII art
 *
 * @param image: Input image (will be converted to grayscale)
 * @param output_width: Desired width of ASCII output (height scaled
 * proportionally)
 * @return: String containing the ASCII art
 */
string imageToAscii(Mat &image, int output_width) {
  // Convert to grayscale if not already
  Mat grayscale;
  if (image.channels() == 3) {
    cvtColor(image, grayscale, COLOR_BGR2GRAY);
  } else {
    grayscale = image.clone();
  }

  // Calculate scaling factor to resize image
  float aspect_ratio = (float)grayscale.rows / (float)grayscale.cols;
  int output_height = (int)(output_width * aspect_ratio *
                            0.5); // 0.5 because chars are taller than wide

  // Resize image to match desired ASCII dimensions
  Mat resized;
  resize(grayscale, resized, Size(output_width, output_height), 0, 0,
         INTER_AREA);

  // Convert each pixel to ASCII
  string ascii_art;
  for (int y = 0; y < resized.rows; y++) {
    for (int x = 0; x < resized.cols; x++) {
      int pixel_value = (int)resized.at<uchar>(y, x);
      ascii_art += mapGrayscaleToAscii(pixel_value);
    }
    ascii_art += '\n';
  }

  return ascii_art;
}

int main(int argc, char **argv) {
  // Check command line arguments
  if (argc < 2) {
    cout << "Usage: " << argv[0] << " <image_path> [output_width]" << endl;
    cout << "  image_path: Path to the input image" << endl;
    cout << "  output_width: Width of ASCII output in characters (default: 100)"
         << endl;
    return -1;
  }

  string image_path = argv[1];
  int output_width = 100; // Default width

  if (argc >= 3) {
    output_width = stoi(argv[2]);
  }

  // Load the image
  Mat image = imread(image_path, IMREAD_COLOR);

  if (image.empty()) {
    cerr << "Error: Could not open or find the image: " << image_path << endl;
    return -1;
  }

  // Convert to ASCII
  string ascii_art = imageToAscii(image, output_width);

  // Output the result
  cout << ascii_art << endl;

  return 0;
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?