Saya menggunakan elemen kanvas html5 untuk mengubah ukuran gambar di browser saya. Ternyata kualitasnya sangat rendah. Saya menemukan ini: Nonaktifkan Interpolasi saat Melakukan Penskalaan <kanvas> tetapi tidak membantu meningkatkan kualitas.
Di bawah ini adalah kode css dan js saya serta gambar yang dipindai dengan Photoshop dan diskalakan di kanvas API.
Apa yang harus saya lakukan untuk mendapatkan kualitas optimal saat menskala gambar di browser?
Catatan: Saya ingin memperkecil gambar besar menjadi kecil, memodifikasi warna di kanvas dan mengirim hasilnya dari kanvas ke server.
CSS:
canvas, img {
image-rendering: optimizeQuality;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
-ms-interpolation-mode: nearest-neighbor;
}
JS:
var $img = $('<img>');
var $originalCanvas = $('<canvas>');
$img.load(function() {
var originalContext = $originalCanvas[0].getContext('2d');
originalContext.imageSmoothingEnabled = false;
originalContext.webkitImageSmoothingEnabled = false;
originalContext.mozImageSmoothingEnabled = false;
originalContext.drawImage(this, 0, 0, 379, 500);
});
Ukuran gambar dengan photoshop:
Ukuran gambar di kanvas:
Edit:
Saya mencoba membuat downscaling dalam lebih dari satu langkah seperti yang diusulkan dalam:
Mengubah ukuran gambar di kanvas HTML5 dan kanvas gambar Html5 drawImage: cara menerapkan antialiasing
Ini adalah fungsi yang saya gunakan:
function resizeCanvasImage(img, canvas, maxWidth, maxHeight) {
var imgWidth = img.width,
imgHeight = img.height;
var ratio = 1, ratio1 = 1, ratio2 = 1;
ratio1 = maxWidth / imgWidth;
ratio2 = maxHeight / imgHeight;
// Use the smallest ratio that the image best fit into the maxWidth x maxHeight box.
if (ratio1 < ratio2) {
ratio = ratio1;
}
else {
ratio = ratio2;
}
var canvasContext = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
var copyContext = canvasCopy.getContext("2d");
var canvasCopy2 = document.createElement("canvas");
var copyContext2 = canvasCopy2.getContext("2d");
canvasCopy.width = imgWidth;
canvasCopy.height = imgHeight;
copyContext.drawImage(img, 0, 0);
// init
canvasCopy2.width = imgWidth;
canvasCopy2.height = imgHeight;
copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
var rounds = 2;
var roundRatio = ratio * rounds;
for (var i = 1; i <= rounds; i++) {
console.log("Step: "+i);
// tmp
canvasCopy.width = imgWidth * roundRatio / i;
canvasCopy.height = imgHeight * roundRatio / i;
copyContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvasCopy.width, canvasCopy.height);
// copy back
canvasCopy2.width = imgWidth * roundRatio / i;
canvasCopy2.height = imgHeight * roundRatio / i;
copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
} // end for
// copy back to canvas
canvas.width = imgWidth * roundRatio / rounds;
canvas.height = imgHeight * roundRatio / rounds;
canvasContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvas.width, canvas.height);
}
Inilah hasilnya jika saya menggunakan ukuran 2 langkah turun:
Inilah hasilnya jika saya menggunakan ukuran 3 langkah turun:
Ini hasilnya jika saya menggunakan ukuran 4 langkah:
Inilah hasilnya jika saya menggunakan ukuran 20 langkah turun:
Catatan: Ternyata dari 1 langkah ke 2 langkah ada peningkatan besar dalam kualitas gambar tetapi semakin banyak langkah yang Anda tambahkan ke proses semakin fuzzy gambar menjadi.
Apakah ada cara untuk menyelesaikan masalah sehingga gambar menjadi lebih kabur, semakin banyak langkah yang Anda tambahkan?
Sunting 2013-10-04: Saya mencoba algoritma dari GameAlchemist. Ini hasilnya dibandingkan dengan Photoshop.
Gambar PhotoShop:
Algoritma GameAlchemist:
sumber
Jawaban:
Karena masalah Anda adalah menurunkan skala gambar Anda, tidak ada gunanya berbicara tentang interpolasi - yang tentang membuat pixel-. Masalahnya di sini adalah downsampling.
Untuk mengurangi sampel gambar, kita perlu mengubah setiap kuadrat p * p piksel dalam gambar asli menjadi satu piksel dalam gambar tujuan.
Untuk alasan kinerja, Browser melakukan downsampling yang sangat sederhana: untuk membangun gambar yang lebih kecil, mereka hanya akan memilih SATU piksel dalam sumber dan menggunakan nilainya untuk tujuan. yang 'lupa' beberapa detail dan menambahkan suara.
Namun ada pengecualian untuk itu: karena downsampling gambar 2X sangat mudah untuk dihitung (rata-rata 4 piksel untuk membuatnya) dan digunakan untuk retina / piksel HiDPI, kasing ini ditangani dengan benar -Peramban menggunakan 4 piksel untuk membuat satu-.
TAPI ... jika Anda menggunakan downsampling 2X beberapa kali, Anda akan menghadapi masalah bahwa kesalahan pembulatan berturut-turut akan menambah terlalu banyak noise.
Yang lebih buruk, Anda tidak akan selalu mengubah ukuran dengan kekuatan dua, dan mengubah ukuran ke kekuatan terdekat + mengubah ukuran terakhir sangat bising.
Apa yang Anda cari adalah downsampling piksel-sempurna, yaitu: pengambilan sampel ulang gambar yang akan mengambil semua piksel input ke dalam akun - apa pun skalanya-.
Untuk melakukan itu kita harus menghitung, untuk setiap piksel input, kontribusinya terhadap satu, dua, atau empat piksel tujuan tergantung apakah proyeksi skala dari piksel input tepat di dalam piksel tujuan, tumpang tindih dengan batas X, perbatasan Y, atau keduanya .
(Skema akan menyenangkan di sini, tetapi saya tidak memilikinya.)
Berikut adalah contoh skala kanvas vs skala sempurna pixel saya pada skala 1/3 dari zombat.
Perhatikan bahwa gambar mungkin diskalakan di Browser Anda, dan .jpegized oleh SO.
Namun kita melihat bahwa ada jauh lebih sedikit kebisingan terutama di rumput di belakang wombat, dan cabang-cabang di sebelah kanan. Suara di bulu membuatnya lebih kontras, tapi sepertinya dia punya rambut putih - tidak seperti gambar sumber -.
Gambar kanan kurang menarik tetapi pasti lebih bagus.
Berikut kode untuk melakukan penurunan skala pixel sempurna:
hasil biola: http://jsfiddle.net/gamealchemist/r6aVp/embedded/result/
fiddle sendiri: http://jsfiddle.net/gamealchemist/r6aVp/
Hal ini cukup rakus memori, karena penyangga mengapung diperlukan untuk menyimpan nilai-nilai menengah gambar tujuan (-> jika kita menghitung hasil kanvas, kita menggunakan 6 kali memori sumber gambar dalam algoritma ini).
Ini juga cukup mahal, karena setiap piksel sumber digunakan apa pun ukuran tujuan, dan kami harus membayar untuk getImageData / putImageDate, cukup lambat juga.
Tetapi tidak ada cara untuk lebih cepat daripada memproses setiap nilai sumber dalam kasus ini, dan situasinya tidak terlalu buruk: Untuk gambar 740 * 556 saya dari wombat, pemrosesan membutuhkan antara 30 dan 40 ms.
sumber
Contoh kanvas cepat dengan kualitas baik: http://jsfiddle.net/9g9Nv/442/
Pembaruan: versi 2.0 (lebih cepat, pekerja web + objek yang dapat ditransfer) - https://github.com/viliusle/Hermite-resize
sumber
Saran 1 - memperpanjang jalur pipa proses
Anda dapat menggunakan step-down seperti yang saya jelaskan di tautan yang Anda rujuk tetapi Anda tampaknya menggunakannya dengan cara yang salah.
Langkah ke bawah tidak diperlukan untuk skala gambar dengan rasio di atas 1: 2 (biasanya, tetapi tidak terbatas pada). Di sinilah Anda perlu melakukan penskalaan drastis yang Anda perlukan untuk membaginya dalam dua (dan jarang, lebih banyak) langkah tergantung pada konten gambar (khususnya di mana frekuensi tinggi seperti garis tipis terjadi).
Setiap kali Anda membuat sampel gambar, Anda akan kehilangan detail dan informasi. Anda tidak dapat mengharapkan gambar yang dihasilkan sejelas aslinya.
Jika Anda kemudian memperkecil gambar dalam banyak langkah, Anda akan kehilangan banyak informasi secara total dan hasilnya akan buruk seperti yang Anda perhatikan.
Coba hanya dengan satu langkah ekstra, atau di atas dua.
Konvolusi
Dalam kasus Photoshop perhatikan bahwa itu menerapkan konvolusi setelah gambar telah sampel ulang, seperti mempertajam. Ini bukan hanya interpolasi dwi-kubik yang terjadi sehingga untuk sepenuhnya meniru Photoshop kita perlu juga menambahkan langkah-langkah yang dilakukan Photoshop (dengan pengaturan default).
Untuk contoh ini saya akan menggunakan jawaban asli saya yang Anda rujuk di posting Anda, tetapi saya telah menambahkan lilitan yang tajam padanya untuk meningkatkan kualitas sebagai proses posting (lihat demo di bawah).
Berikut ini adalah kode untuk menambahkan filter mempertajam (ini didasarkan pada filter konvolusi generik - Saya meletakkan matriks bobot untuk mempertajam di dalamnya serta faktor campuran untuk menyesuaikan pengucapan efek):
Pemakaian:
Nilai tersebut
mixFactor
adalah antara [0,0, 1.0] dan memungkinkan Anda mengecilkan efek mempertajam - rule-of-thumb: semakin sedikit ukuran semakin sedikit efek yang dibutuhkan.Fungsi (berdasarkan cuplikan ini ):
Hasil dari menggunakan kombinasi ini adalah:
DEMO ONLINE DI SINI
Bergantung pada seberapa banyak penajaman yang ingin Anda tambahkan ke campuran, Anda bisa mendapatkan hasil dari "buram" default menjadi sangat tajam:
Saran 2 - implementasi algoritma tingkat rendah
Jika Anda ingin mendapatkan hasil terbaik dari segi kualitas, Anda harus menggunakan level rendah dan mempertimbangkan untuk menerapkan, misalnya algoritma baru ini untuk melakukannya.
Lihat Interpolation-Dependent Image Downsampling (2011) dari IEEE.
Berikut ini tautan ke kertas secara lengkap (PDF) .
Tidak ada implementasi dari algoritma ini di JavaScript AFAIK pada saat ini sehingga Anda siap untuk melakukan hand-full jika Anda ingin terlibat dalam tugas ini.
Intinya adalah (kutipan dari kertas):
Abstrak
(lihat tautan yang disediakan untuk semua detail, rumus, dll.)
sumber
Jika Anda ingin menggunakan kanvas saja, hasil terbaik adalah dengan beberapa downsteps. Tapi itu belum baik. Untuk kualitas yang lebih baik Anda perlu implementasi js murni. Kami baru saja merilis pica - downscaler kecepatan tinggi dengan kualitas / kecepatan variabel. Singkatnya, ini mengubah ukuran 1280 * 1024px dalam ~ 0,1s, dan gambar 5000 * 3000px dalam 1s, dengan kualitas tertinggi (filter lanczos dengan 3 lobus). Pica memiliki demo , tempat Anda dapat bermain dengan gambar, tingkat kualitas, dan bahkan mencobanya di perangkat seluler.
Pica belum memiliki topeng unsharp, tapi itu akan ditambahkan segera. Itu jauh lebih mudah daripada menerapkan filter konvolusi kecepatan tinggi untuk mengubah ukuran.
sumber
Mengapa menggunakan kanvas untuk mengubah ukuran gambar? Browser modern semuanya menggunakan interpolasi bikubik - proses yang sama digunakan oleh Photoshop (jika Anda melakukannya dengan benar) - dan mereka melakukannya lebih cepat daripada proses kanvas. Cukup tentukan ukuran gambar yang Anda inginkan (gunakan hanya satu dimensi, tinggi atau lebar, untuk mengubah ukuran secara proporsional).
Ini didukung oleh sebagian besar browser, termasuk versi IE yang lebih baru. Versi sebelumnya mungkin memerlukan CSS khusus browser .
Fungsi sederhana (menggunakan jQuery) untuk mengubah ukuran gambar adalah seperti ini:
Kemudian gunakan saja nilai yang dikembalikan untuk mengubah ukuran gambar dalam satu atau kedua dimensi.
Jelas ada perbaikan yang berbeda yang bisa Anda lakukan, tetapi ini menyelesaikan pekerjaan.
Rekatkan kode berikut ke konsol halaman ini dan saksikan apa yang terjadi pada gravatars:
sumber
Bukan jawaban yang tepat untuk orang yang benar-benar perlu mengubah ukuran gambar itu sendiri, tetapi hanya untuk mengecilkan ukuran file .
Saya memiliki masalah dengan gambar "langsung dari kamera", yang sering diunggah pelanggan saya dalam format JPEG "tidak terkompresi".
Tidak begitu terkenal adalah, bahwa kanvas mendukung (di sebagian besar browser 2017) untuk mengubah kualitas JPEG
Dengan trik ini saya dapat mengurangi foto 4k x 3k dengan> 10Mb menjadi 1 atau 2Mb, tentu tergantung pada kebutuhan Anda.
Lihat di sini
sumber
Berikut ini adalah layanan Angular yang dapat digunakan kembali untuk mengubah ukuran gambar / kanvas berkualitas tinggi: https://gist.github.com/fisch0920/37bac5e741eaec60e983
Layanan ini mendukung lanczos convolution dan step-wise downscaling. Pendekatan konvolusi adalah kualitas yang lebih tinggi dengan biaya lebih lambat, sedangkan pendekatan penurunan langkah-bijaksana menghasilkan hasil yang cukup antialiased dan secara signifikan lebih cepat.
Contoh penggunaan:
sumber
Ini adalah filter ubah ukuran Hermite yang ditingkatkan yang menggunakan 1 pekerja sehingga jendela tidak membeku.
https://github.com/calvintwr/blitz-hermite-resize
sumber
Saya menemukan solusi yang tidak perlu mengakses langsung data piksel dan mengulanginya untuk melakukan downsampling. Tergantung pada ukuran gambar, ini bisa menjadi sumber daya yang sangat intensif, dan akan lebih baik untuk menggunakan algoritma internal browser.
Fungsi drawImage () menggunakan metode interpolasi linier, tetangga-tetangga terdekat. Itu bekerja dengan baik ketika Anda tidak mengubah ukuran lebih dari setengah ukuran aslinya .
Jika Anda beralih ke hanya mengubah ukuran maks satu setengah pada satu waktu, hasilnya akan cukup baik, dan jauh lebih cepat daripada mengakses data piksel.
Fungsi ini downsample menjadi setengah sekaligus hingga mencapai ukuran yang diinginkan:
sumber
Mungkin Anda dapat mencoba ini, yang selalu saya gunakan dalam proyek saya. Dengan cara ini Anda tidak hanya bisa mendapatkan gambar berkualitas tinggi, tetapi elemen lain di kanvas Anda.
sumber
bukannya 0,85 , jika kita menambahkan 1,0 . Anda akan mendapatkan jawaban yang tepat.
Anda bisa mendapatkan gambar yang jelas dan cerah. Silakan periksa
sumber
Saya benar-benar mencoba untuk menghindari menjalankan melalui data gambar, terutama pada gambar yang lebih besar. Jadi saya datang dengan cara yang agak sederhana untuk mengurangi ukuran gambar dengan sopan tanpa batasan atau batasan menggunakan beberapa langkah tambahan. Rutin ini turun ke setengah langkah serendah mungkin sebelum ukuran target yang diinginkan. Kemudian timbangan itu menjadi dua kali ukuran target dan kemudian setengah lagi. Kedengarannya lucu pada awalnya, tetapi hasilnya sangat bagus dan pergi ke sana dengan cepat.
sumber
context.scale(xScale, yScale)
sumber
DEMO : Mengubah ukuran gambar dengan fiddler Demo Kanvas JS dan HTML.
Anda mungkin menemukan 3 metode berbeda untuk melakukan pengubahan ukuran ini, yang akan membantu Anda memahami bagaimana kode bekerja dan mengapa.
https://jsfiddle.net/1b68eLdr/93089/
Kode lengkap dari kedua demo, dan metode TypeScript yang mungkin ingin Anda gunakan dalam kode Anda, dapat ditemukan di proyek GitHub.
https://github.com/eyalc4/ts-image-resizer
Ini adalah kode terakhir:
sumber