Rumah >pembangunan bahagian belakang >masalah PHP >Ajar anda helah untuk menjana imej menggunakan aksara ASCII

Ajar anda helah untuk menjana imej menggunakan aksara ASCII

醉折花枝作酒筹
醉折花枝作酒筹ke hadapan
2021-07-22 15:50:093348semak imbas

ASCII ialah sistem pengekodan komputer berdasarkan abjad Latin, terutamanya digunakan untuk memaparkan bahasa Inggeris moden dan bahasa Eropah Barat yang lain. Malah, aksara ASCII bukan sahaja boleh digunakan sebagai standard pertukaran maklumat, tetapi juga boleh digunakan untuk menjana imej Hari ini kami akan memperkenalkannya.

Ajar anda helah untuk menjana imej menggunakan aksara ASCII

Selalunya terdapat gambar yang dibuat daripada watak-watak di Internet, seperti ini:

Ajar anda helah untuk menjana imej menggunakan aksara ASCII

Fikirkanlah, yang utama di sini Beberapa pengetahuan digunakan, termasuk:

  • Menghuraikan warna piksel daripada imej (juga dikenali sebagai nilai RGB)

  • Pemprosesan penyahwarnaan

  • Pemetaan piksel kepada aksara

Sebagai bahasa terbaik di dunia, mudah untuk melaksanakan fungsi menarik dengan PHP. Pelaksanaan khusus diterangkan di bawah.

1. Analisis warna piksel dalam imej

Untuk menganalisis warna piksel dalam imej, kita perlu memahami format storan imej Di sini kita mengambil imej BMP sebagai contoh. apa? Tidak dapat mencari gambar BMP dalam talian? Hanya gunakan QQ untuk mengambil tangkapan skrin dan simpan sebagai BMP.

Imej BMP tidak mengandungi data piksel bermula dari bait pertama fail, tetapi setiap pengepala fail 14 bait, yang menyimpan maklumat meta fail. Di sebelahnya ialah struktur pengepala imej 40-bait, yang menyimpan maklumat meta yang berkaitan dengan imej.

Menyenaraikan setiap medan pengepala fail dan struktur pengepala imej secara terperinci agak terlalu membosankan (lihat lampiran untuk maklumat pengepala terperinci). Untuk menghuraikan piksel imej, anda hanya memerlukan 4 maklumat ini:

  • Saiz keseluruhan fail imej (bait ke-3 hingga ke-6 fail)

  • Di mana dalam fail data piksel bermula (11~14 bait)

  • Lebar dan tinggi imej (lebar: 19~22 bait, ketinggian: 23 ~26 bait)

  • Berapa banyak bait yang diduduki oleh satu piksel imej (pada 29~30 bait)

Ingin menghuraikan Ke dapatkan data dalam binari, anda boleh menggunakan unpack() digabungkan dengan substr():

$data = file_get_contents('image.bmp');$ret = unpack('v/Vsize/v/v/VpixelStart/V/Vwidth/Vheight/v/vbytePerPixel/V*6',
    substr($data, 0x0, 54));/**
 * $ret的内容:
 * array (
 *     'size' => 706554,
 *     'pixelStart' => 54,
 *     'width' => 500,
 *     'height' => 471,
 *     'bytePerPixel' => 24,
 * );
 */

2 Dapatkan warna piksel dan keluarkan warna

Seperti yang anda boleh ketahui dari bahagian sebelumnya, kami mahu Untuk gambar yang diproses, data piksel bermula dari bait ke-54 fail, dan setiap data piksel menduduki 24 bit. Di antara 24 bit ini, nilai R (merah), G (hijau), dan B (biru) masing-masing menempati 8 bit (1 bait).

Jika saya ingin mendapatkan nilai RGB bagi baris x dan lajur y gambar, maka kedudukan nilai RGB yang sepadan hendaklah dikira seperti ini:

像素(x, y)的 B 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y)
像素(x, y)的 G 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 1
像素(x, y)的 R 值偏移 = 像素数据开始位置 + 3 * (图片宽度 * x + y) + 2

Cari nilai daripada tiga warna utama daripada formula Ia disusun dalam susunan BGR, bukan susunan RGB biasa.

Jika anda mengikuti kaedah ini dan melukis piksel satu demi satu pada kanvas mengikut urutan, anda akan mendapati gambar yang terhasil adalah terbalik Ini kerana maklumat piksel gambar disimpan secara terbalik piksel di penjuru kiri sebelah atas sebenarnya berada di hujung fail, jadi jika anda ingin mendapatkan gambar lurus ke hadapan, data piksel harus diambil seperti ini:

像素(x, y)的 B 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 3
像素(x, y)的 G 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 2
像素(x, y)的 R 值偏移 = 文件大小 - 3 * (图片宽度 * x + y) - 1

Warna piksel diambil, tetapi imej ASCII terakhir adalah hitam dan putih. Bagaimana untuk membuang warna? Terdapat banyak algoritma untuk penyingkiran warna, berikut adalah yang paling mudah dan paling kasar:

新的R、G、B值 = [min(R, G, B) + max(R, G, B)] / 2;

Piksel hitam dan putih, R, G dan B semuanya mempunyai nilai yang sama. Nilai ini boleh dipanggil kecerahan piksel

Akhir sekali, operasi mengambil piksel boleh ditakrifkan sebagai fungsi:

function getPixelColor($x, $y) {
    global $width, $size, $data;
    $b = ord($data[$size - 3 * ($width * $x + $y) - 3]);
    $g = ord($data[$size - 3 * ($width * $x + $y) - 2]);
    $r = ord($data[$size - 3 * ($width * $x + $y) - 1]);
    return (min($r, $g, $b) + max($r, $g, $b)) >> 1;
}

3 Pemetaan piksel kepada aksara

Dalam langkah terakhir, kami telah untuk memetakan setiap piksel imej Tukar cahaya kepada aksara ascii. Watak ASCII sendiri tidak mempunyai warna warna. Tetapi jika anda menyusun "#" dan "." menjadi petak 100x100, secara visual "#" akan menjadi lebih gelap daripada ".".

Kita boleh mengambil beberapa aksara untuk mewakili kecerahan piksel yang berbeza Apabila kecerahan piksel tertentu berada dalam julat tertentu, gantikannya dengan tahap aksara yang sepadan:

function getChar($colorValue) {
    $map = '@#mdohsy+/-:.` ';
    return $map[(int) ($colorValue / 18)];
}

dan Satu masalah: Jika setiap piksel digantikan dengan aksara, peta aksara output akan menjadi sangat besar. Jadi yang terbaik adalah menggunakan aksara untuk menggantikan blok piksel NxN dalam imej asal. Kecerahan keseluruhan blok piksel ialah purata kecerahan setiap piksel dalam blok.

Masalah di atas telah selesai Akhirnya, saya mengambil senyuman Mona Lisa untuk menguji:

Ajar anda helah untuk menjana imej menggunakan aksara ASCII

Ajar anda helah untuk menjana imej menggunakan aksara ASCII

Kesannya. cukup bagus :-). Jika latar belakang terminal berwarna putih, jujukan aksara yang mewakili kecerahan boleh diterbalikkan:

// $map = '@#mdohsy+/-:.` ';
$map = ' `.:-/+yshodm#@'; // 反过来

附录

完整代码

<?php $data = file_get_contents(&#39;timg.bmp&#39;);$ret = unpack(&#39;v/Vsize/v/v/VpixelStart/V/Vwidth/Vheight/v/vbytePerPixel/V*6&#39;, substr($data, 0x0, 54));$size = $ret[&#39;size&#39;];$offset = $ret[&#39;pixelStart&#39;];$width = $ret[&#39;width&#39;];$height = $ret[&#39;height&#39;];$bitDepth = $ret[&#39;bytePerPixel&#39;];$pixelLenPerChar = 4;$charImgWidth = (int) ($width / $pixelLenPerChar);$charImgHeight = (int) ($height / $pixelLenPerChar);for ($i = 0; $i !== $charImgHeight; $i++) {    $buf = &#39;&#39;;    for ($j = 0; $j !== $charImgWidth; $j++) {        $sum = 0;        for ($k = 0; $k !== $pixelLenPerChar; $k++) {            for ($l = 0; $l !== $pixelLenPerChar; $l++) {                $sum += getPixelColor($pixelLenPerChar * $i + $k, $pixelLenPerChar * $j + $l);
            }
        }        $sum = (int) ($sum / $pixelLenPerChar / $pixelLenPerChar);        $buf = getChar($sum) . $buf;
    }    echo $buf . PHP_EOL;
}function getPixelColor($x, $y) {
    global $width, $size, $data;    $b = ord($data[$size - 3 * ($width * $x + $y) - 3]);    $g = ord($data[$size - 3 * ($width * $x + $y) - 2]);    $r = ord($data[$size - 3 * ($width * $x + $y) - 1]);    return (min($r, $g, $b) + max($r, $g, $b)) >> 1;
}function getChar($colorValue) {
    $map = '@#mdohsy+/-:.` ';    return $map[(int) ($colorValue / 18)];
}

BMP文件头格式

偏移 大小(字节) 含义 本文中图片示例值
0 2 固定为”BM”两个字符的编码 0x42 0x4d
2 4 文件大小 0x000ac7fa
6 4 保留字段,一般为 0 0x00000000
10 4 像素数据起始处偏移 0x00000036

BMP图片头格式

偏移 大小(字节) 含义 本文中图片示例值
14 4 图片头的大小(字节) 0x00000028
18 4 图片的宽度 0x000001f4
22 4 图片的高度 0x000001d7
26 2 图像的帧数(静态图都是1) 0x0001
28 2 一个像素占的比特位数 0x0018
30 4 保留字段,一般为 0 0x000000
34 4 像素数据占用的总字节数 0x000ac7c4
38 4 保留字段,一般为 0 0x000000
42 4 保留字段,一般为 0 0x000000
46 4 保留字段,一般为 0 0x000000
50 4 保留字段,一般为 0 0x000000

推荐学习:php视频教程

Atas ialah kandungan terperinci Ajar anda helah untuk menjana imej menggunakan aksara ASCII. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:csdn.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam