今回は、画像から色の濃淡のみで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;
}