• TOP
  • NEWS
  • ABOUT
  • SERVICE
  • WORKS
  • PROJECT
  • BLOG
  • CONTACT
taziku
  • TOP
  • NEWS
  • ABOUT
  • SERVICE
  • WORKS
  • PROJECT
  • BLOG
  • CONTACT

Claude 3 で画像をピクセル化するプログラムを生成

2024年4月15日
AI BLOG Technology
Claude 生成AI

前回「Claude 3 で画像連携のクリエイティブコーディング」という記事で、Three.jsを利用して、画像を粒子にして、拡散するというプログラムを生成しましたが、今回は、同じくClaude 3とThree.jsを利用して異なるコーディングを試してみました。

生成したプログラム

入力した画像をピクセル化するようなプログラムを書いてみました。ピクセルアートに変換するにあたって、ピクセル化の粒度も選べるように調整しています。

実際のコード

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Image to Pixel Art Animation</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
  <style>
    body { margin: 0; }
    canvas { display: block; }
  </style>
</head>
<body>
  <script>
    // シーンの設定
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.z = 1;

    const renderer = new THREE.WebGLRenderer({ alpha: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x000000, 0); // 背景を透明に設定
    document.body.appendChild(renderer.domElement);

    let mesh;

    // 画像のURL配列
    const imageUrls = [
      'image1.jpg',
      'image2.jpg',
      'image3.jpg',
      'image4.jpg'
    ];

    let currentImageIndex = 0;

    // 画像の読み込み
    const loader = new THREE.TextureLoader();
    let pixelMaterial;
    loadImage();

    function loadImage() {
      loader.load(imageUrls[currentImageIndex], (texture) => {
        const aspectRatio = texture.image.width / texture.image.height;
        const windowAspectRatio = window.innerWidth / window.innerHeight;

        let imageWidth, imageHeight;
        if (aspectRatio > windowAspectRatio) {
          imageWidth = 1;
          imageHeight = 1 / aspectRatio;
        } else {
          imageWidth = aspectRatio;
          imageHeight = 1;
        }

        const geometry = new THREE.PlaneGeometry(imageWidth, imageHeight);

        if (pixelMaterial) {
          pixelMaterial.map = texture;
          pixelMaterial.needsUpdate = true;
        } else {
          pixelMaterial = new THREE.MeshBasicMaterial({ map: texture, transparent: true });
          mesh = new THREE.Mesh(geometry, pixelMaterial);
          scene.add(mesh);
        }

        // アニメーションの開始
        animatePixelation();
      });
    }

    // ピクセル化アニメーション
    function animatePixelation() {
      let pixelSize = 1;
      const maxPixelSize = 3;
      const duration = 2000; // アニメーションの時間(ミリ秒)
      const startTime = performance.now();

      function animate() {
        const elapsedTime = performance.now() - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        pixelSize = Math.floor(progress * (maxPixelSize - 1)) + 1;

        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = pixelMaterial.map.image.width;
        canvas.height = pixelMaterial.map.image.height;
        ctx.drawImage(pixelMaterial.map.image, 0, 0);

        if (pixelSize > 1) {
          const pixelCanvas = document.createElement('canvas');
          pixelCanvas.width = canvas.width;
          pixelCanvas.height = canvas.height;
          const pixelCtx = pixelCanvas.getContext('2d');
          pixelCtx.imageSmoothingEnabled = false;

          const colorPalette = [
            '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff',
            '#ffff00', '#ff00ff', '#00ffff', '#800000', '#008000',
            '#000080', '#808000', '#800080', '#008080', '#808080'
          ];

          for (let y = 0; y < canvas.height; y += pixelSize) {
            for (let x = 0; x < canvas.width; x += pixelSize) {
              const imageData = ctx.getImageData(x, y, pixelSize, pixelSize);
              let totalR = 0, totalG = 0, totalB = 0;
              for (let i = 0; i < imageData.data.length; i += 4) {
                totalR += imageData.data[i];
                totalG += imageData.data[i + 1];
                totalB += imageData.data[i + 2];
              }
              const avgR = totalR / (imageData.data.length / 4);
              const avgG = totalG / (imageData.data.length / 4);
              const avgB = totalB / (imageData.data.length / 4);

              let minDistance = Infinity;
              let closestColor = '';
              for (const color of colorPalette) {
                const [pr, pg, pb] = hexToRGB(color);
                const distance = Math.sqrt((avgR - pr) ** 2 + (avgG - pg) ** 2 + (avgB - pb) ** 2);
                if (distance < minDistance) {
                  minDistance = distance;
                  closestColor = color;
                }
              }

              pixelCtx.fillStyle = closestColor;
              pixelCtx.fillRect(x, y, pixelSize, pixelSize);
            }
          }

          pixelMaterial.map.image = pixelCanvas;
        } else {
          pixelMaterial.map.image = canvas;
        }

        pixelMaterial.map.needsUpdate = true;

        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // 次の画像をロード
          currentImageIndex = (currentImageIndex + 1) % imageUrls.length;
          setTimeout(loadImage, 1000); // 1秒後に次の画像をロード
        }
      }

      animate();
    }

    // RGB値に変換する関数
    function hexToRGB(hex) {
      const r = parseInt(hex.slice(1, 3), 16);
      const g = parseInt(hex.slice(3, 5), 16);
      const b = parseInt(hex.slice(5, 7), 16);
      return [r, g, b];
    }

    // ウィンドウのリサイズ処理
    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    }

    // ウィンドウのリサイズイベントリスナー
    window.addEventListener('resize', onWindowResize);

    // レンダリング
    function render() {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }
    render();
  </script>
</body>
</html>

動作デモ

LLMに的確に指示しないと時間がかかる

前回と異なりかなり時間がかかってしまいました。前回はあまり考えずに指示しても形になりましたが、LLMに適した指示の形をうまく形成していかないと、自分で書いたほうが早いということになりがちだと感じました。

指示を体系化して、より高い精度を出せるように調整していきたい。

※当サイトに掲載されている商標、一部画像、スクリ-ンショット、文章に置いては著作権侵害を目的に利用しておらず、第三十二条で定められる引用の範囲で使用しています。万が一問題があれば、お問い合わせからご連絡ください。即刻削除いたします。また、本ブログは業務の研究開発のためのものとなり、一部、弊社に関連性が無いものも掲載しております。

AIの最新情報を随時発信中

Xやnoteでは、AI・生成AI・LLMなどの最新情報や、ChatGPTやMidjourneyのプロンプトテクニックを連載中!フォローよろしくお願いします。

生成AI・AIの導入・研修・DXの支援はtazikuへ

生成AI・LLMなど、AIを活用したAIの導入・DXコンサルティング、AI領域の研修・講演などのご相談はお気軽にお問い合わせフォーム、もしくは生成AIソリューションAI CREATIVE BASEから、ご相談・お問い合せください。

PREV AIアニメプロジェクト 楽曲の生成実験を開始
NEXT Claude 3 の連鎖プロンプト「プロンプトチェーン」を試す
Related Post
Stable Diffusionの「Poor man’s outpainting」を利用してアウトペインティング
2023年の振り返りと、2024年の展望
ChatGPT有料プランの解約方法について解説
MidJourney v6で、D2Cシャンプーのパッケージをデザイン
Bing AIチャットとChatGPTと考えるWEBサイト戦略
「EasyPromptAnime」で自分の好きなモデルを利用する
Related Post
進化するMidjourney v7が描く次世代のAI画像生成
Claude 3.5の新機能 新モデル登場とPC操作機能
Claude 3 の連鎖プロンプト「プロンプトチェーン」を試す
Claude 3で登場人物の会話を生成する
Claude 3 でXMLタグを利用する
Claude 3 の入力データの取り扱いについて

« PREV

Back to list

NEXT »

  • 投稿検索

  • ABOUT US?

    tazikuは東京・名古屋を拠点に活動するクリエイティブスタジオです。
    AI・生成AI・LLMとクリエイティブを掛け合わせ、新しいクリエイティブを提供します。
    Works
    Service
    Contact
  • AI CREATIVE BASE

    デザイン、ビジュアル、音声、空間演出。生成AIでクリエイティブワークフローに革新を与え、ビジネスの成果を最大化します。

    詳細を見る

  • MENU

    • BLOG
      • Think
      • Creative
      • Technology
        • AI
        • メタバース
    • Project
      • AIアニメプロジェクト
      • どうくつたんけん
  • NEW POST

    • 進化するMidjourney v7が描く次世代のAI画像生成
    • Claude 3.5の新機能 新モデル登場とPC操作機能
    • Claude 3 の連鎖プロンプト「プロンプトチェーン」を試す
    • Claude 3 で画像をピクセル化するプログラムを生成
    • Claude 3で登場人物の会話を生成する
© 2021 taziku / 株式会社タジク Based in Tokyo and Nagoya | プライバシーポリシー