Skip to content

演習 D - 模写アプリ改造

1.2 で紹介したサンプル「模写アプリ」を改造して、異なるスタイルで絵を描くようにします。

線で描く

# include <Siv3D.hpp>

// 2 つの画像の距離を計算する関数
double Diff(const Image& a, const Image& b)
{
	const Color* pA = a.data();
	const Color* pB = b.data();
	const Color* const pAEnd = (pA + a.num_pixels());
	double d = 0.0;

	// すべてのピクセルに対して
	while (pA != pAEnd)
	{
		d += AbsDiff(pA->r, pB->r) + AbsDiff(pA->g, pB->g) + AbsDiff(pA->b, pB->b);
		++pA;
		++pB;
	}

	return d;
}

void Main()
{
	// 目標とする画像をファイルダイアログで選択、シーンのサイズにフィットするようリサイズ
	const Image target = Dialog::OpenImage().fit(Scene::Size());

	// 現在の画像
	Image image{ target.size(), Palette::White };

	// 直前の画像
	Image old = image;

	// 現在の画像を表示するための動的テクスチャ
	DynamicTexture texture{ image };

	// 目標との距離
	double d1 = Diff(target, image);

	while (System::Update())
	{
		for (int32 i = 0; i < 100; ++i)
		{
			// ランダムな始点座標
			const Point startPos = RandomPoint(Rect{ image.size() });

			// ランダムな終点座標
			const Point endPos{ (startPos.x + Random(-10, 10)), (startPos.y + Random(-10, 10)) };

			// ランダムな色
			const ColorF color{ Random(), Random(), Random(), Random() };

			// 太さ
			const int32 thickness = 1;

			// 線分を現在の画像に書き込む
			Line{ startPos, endPos }.paint(image, thickness, color);

			// 目標との距離を計算
			const double d2 = Diff(target, image);

			if (d2 < d1) // 目標に近づいていたら採用
			{
				d1 = d2;
				old = image;
			}
			else // 近づいていなかったら元に戻す
			{
				image = old;
			}
		}

		// 動的テクスチャを更新
		texture.fill(image);

		// テクスチャを画面の中心に描画
		texture.drawAt(Scene::Center());

		// 保存ボタン
		if (SimpleGUI::Button(U"Save", Vec2{ 660, 550 }))
		{
			// 現在の画像をファイルダイアログ経由で保存
			image.saveWithDialog();
		}
	}
}

丸タイル

# include <Siv3D.hpp>

// 2 つの画像の距離を計算する関数
double Diff(const Image& a, const Image& b)
{
	const Color* pA = a.data();
	const Color* pB = b.data();
	const Color* const pAEnd = (pA + a.num_pixels());
	double d = 0.0;

	// すべてのピクセルに対して
	while (pA != pAEnd)
	{
		d += AbsDiff(pA->r, pB->r) + AbsDiff(pA->g, pB->g) + AbsDiff(pA->b, pB->b);
		++pA;
		++pB;
	}

	return d;
}

void Main()
{
	// 目標とする画像をファイルダイアログで選択、シーンのサイズにフィットするようリサイズ
	const Image target = Dialog::OpenImage().fit(Scene::Size());

	// 現在の画像
	Image image{ target.size(), Palette::White };

	// 直前の画像
	Image old = image;

	// 現在の画像を表示するための動的テクスチャ
	DynamicTexture texture{ image };

	// 目標との距離
	double d1 = Diff(target, image);

	while (System::Update())
	{
		for (int32 i = 0; i < 100; ++i)
		{
			// ランダムな座標
			Point pos = RandomPoint(Rect{ image.size() });

			// 10 で割る (小数以下切り捨て)
			pos /= 10;

			// 10 をかける
			pos *= 10;

			// ランダムな色
			const ColorF color{ Random(), Random(), Random(), Random() };

			// 円を現在の画像に書き込む
			Circle{ pos, 4 }.paint(image, color);

			// 目標との距離を計算
			const double d2 = Diff(target, image);

			if (d2 < d1) // 目標に近づいていたら採用
			{
				d1 = d2;
				old = image;
			}
			else // 近づいていなかったら元に戻す
			{
				image = old;
			}
		}

		// 動的テクスチャを更新
		texture.fill(image);

		// テクスチャを画面の中心に描画
		texture.drawAt(Scene::Center());

		// 保存ボタン
		if (SimpleGUI::Button(U"Save", Vec2{ 660, 550 }))
		{
			// 現在の画像をファイルダイアログ経由で保存
			image.saveWithDialog();
		}
	}
}

モノクロ

# include <Siv3D.hpp>

// 2 つの画像の距離を計算する関数
double Diff(const Image& a, const Image& b)
{
	const Color* pA = a.data();
	const Color* pB = b.data();
	const Color* const pAEnd = (pA + a.num_pixels());
	double d = 0.0;

	// すべてのピクセルに対して
	while (pA != pAEnd)
	{
		d += AbsDiff(pA->r, pB->r) + AbsDiff(pA->g, pB->g) + AbsDiff(pA->b, pB->b);
		++pA;
		++pB;
	}

	return d;
}

void Main()
{
	// 目標とする画像をファイルダイアログで選択、シーンのサイズにフィットするようリサイズ
	const Image target = Dialog::OpenImage().fit(Scene::Size());

	// 現在の画像
	Image image{ target.size(), Palette::White };

	// 直前の画像
	Image old = image;

	// 現在の画像を表示するための動的テクスチャ
	DynamicTexture texture{ image };

	// 目標との距離
	double d1 = Diff(target, image);

	while (System::Update())
	{
		for (int32 i = 0; i < 100; ++i)
		{
			// ランダムな座標
			const Point pos = RandomPoint(Rect{ image.size() });

			// ランダムな色 (rgb, a)
			const ColorF color{ Random(), Random() };

			// ランダムな半径
			const int32 size = Random(1, 10);

			// 円を現在の画像に書き込む
			Circle{ pos, size }.paint(image, color);

			// 目標との距離を計算
			const double d2 = Diff(target, image);

			if (d2 < d1) // 目標に近づいていたら採用
			{
				d1 = d2;
				old = image;
			}
			else // 近づいていなかったら元に戻す
			{
				image = old;
			}
		}

		// 動的テクスチャを更新
		texture.fill(image);

		// テクスチャを画面の中心に描画
		texture.drawAt(Scene::Center());

		// 保存ボタン
		if (SimpleGUI::Button(U"Save", Vec2{ 660, 550 }))
		{
			// 現在の画像をファイルダイアログ経由で保存
			image.saveWithDialog();
		}
	}
}