├── .gitignore ├── assets ├── img │ ├── amla.jpg │ └── img.jpg └── lib │ └── sgl.js ├── deploy.py ├── 404.html ├── p5js └── index.html ├── playlist-compare └── index.html ├── README.zh-CN.md ├── README.md ├── LICENSE ├── demo.html ├── reset.css ├── index.html ├── .github └── workflows │ └── pages.yml ├── webgl ├── index.html ├── quadrangle.html ├── dip.html ├── texture.html ├── triangle.html ├── transform.html ├── audio-webgl.html ├── audio-webgl-v3.html ├── video.html ├── audio-webgl-v2.html └── dip-webgl.html ├── jo └── a.html ├── ncmdaily └── index.html ├── lastfm-export └── index.html └── dip ├── t.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .venv 3 | -------------------------------------------------------------------------------- /assets/img/amla.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldshensheep/toyweb/main/assets/img/amla.jpg -------------------------------------------------------------------------------- /assets/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldshensheep/toyweb/main/assets/img/img.jpg -------------------------------------------------------------------------------- /deploy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | exclude_dirs = ['.github', 5 | '.git', '.idea', 'deploy.py', '.gitignore'] 6 | 7 | for root, dirs, files in os.walk('./'): 8 | os.mkdir('dist') 9 | files = set(dirs+files) - set(exclude_dirs) 10 | print(files) 11 | for f in files: 12 | shutil.move(f, 'dist') 13 | break 14 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My App 5 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /p5js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 12 | 13 | 14 | 15 | 30 | 31 | -------------------------------------------------------------------------------- /playlist-compare/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 歌单匹配 9 | 10 | 11 | 12 |
13 | site had move to https://nextjs-demo-tau-beige.vercel.app/playlist-compare/ 15 |
16 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | [English](./README.md) | 简体中文 2 | 3 | ## toyweb 4 | 5 | html js 玩具 6 | 7 | 8 | ### [LastFM Export](./lastfm-export) [➡️ 预览](https://oldshensheep.github.io/toyweb/lastfm-export/) 9 | 10 | 导出 last.fm 的数据到 csv. 11 | 12 | ### [Playlist Compare](./playlist-compare)[➡️ 预览](https://oldshensheep.github.io/toyweb/playlist-compare/) 13 | 14 | 网易云音乐和 QQ 音乐的歌单比对。(不完善) 15 | 16 | ### [NCMDaily](./ncmdaily)[➡️ 预览](https://oldshensheep.github.io/toyweb/ncmdaily/) 17 | 18 | 19 | 浏览我的网易云音乐每日推荐。 20 | 21 | ### [Digital Image Processing](./dip) [➡️ 预览](https://oldshensheep.github.io/toyweb/dip/) 22 | 23 | 数字图像处理。纯 javascript。 24 | 25 | - 变成灰度图 26 | - 反转 27 | - 量化 28 | - 高斯滤波器 29 | - 拉普拉斯滤波器 30 | - 最大值滤波器 31 | - ... 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](./README.zh-CN.md) 2 | 3 | ## toyweb 4 | 5 | html js toys 6 | 7 | 8 | ### [LastFM Export](./lastfm-export) [➡️ Preview](https://oldshensheep.github.io/toyweb/lastfm-export/) 9 | 10 | export your last.fm data to csv. 11 | 12 | ### [Playlist Compare](./playlist-compare)[➡️ Preview](https://oldshensheep.github.io/toyweb/playlist-compare/) 13 | 14 | playlist compare for netease cloud music and qqmusic. (incomplete) 15 | 16 | ### [NCMDaily](./ncmdaily)[➡️ Preview](https://oldshensheep.github.io/toyweb/ncmdaily/) 17 | 18 | browse my netease cloud music daily recommendation. 19 | 20 | ### [Digital Image Processing](./dip) [➡️ Preview](https://oldshensheep.github.io/toyweb/dip/) 21 | 22 | digital image processing. pure javascript. 23 | 24 | - grayscale 25 | - invert 26 | - quantify 27 | - gaussian filter 28 | - laplace 29 | - max filter 30 | - ... 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 oldshensheep 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 |
13 | message:{{ message }} 14 | 15 |
16 | 17 | 18 | 19 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /reset.css: -------------------------------------------------------------------------------- 1 | 2 | html, body, div, span, applet, object, iframe, 3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 4 | a, abbr, acronym, address, big, cite, code, 5 | del, dfn, em, img, ins, kbd, q, s, samp, 6 | small, strike, strong, sub, sup, tt, var, 7 | b, u, i, center, 8 | dl, dt, dd, ol, ul, li, 9 | fieldset, form, label, legend, 10 | table, caption, tbody, tfoot, thead, tr, th, td, 11 | article, aside, canvas, details, embed, 12 | figure, figcaption, footer, header, hgroup, 13 | menu, nav, output, ruby, section, summary, 14 | time, mark, audio, video { 15 | margin: 0; 16 | padding: 0; 17 | border: 0; 18 | font-size: 100%; 19 | font: inherit; 20 | vertical-align: baseline; 21 | } 22 | /* HTML5 display-role reset for older browsers */ 23 | article, aside, details, figcaption, figure, 24 | footer, header, hgroup, menu, nav, section { 25 | display: block; 26 | } 27 | body { 28 | line-height: 1; 29 | } 30 | ol, ul { 31 | list-style: none; 32 | } 33 | blockquote, q { 34 | quotes: none; 35 | } 36 | blockquote:before, blockquote:after, 37 | q:before, q:after { 38 | content: ''; 39 | content: none; 40 | } 41 | table { 42 | border-collapse: collapse; 43 | border-spacing: 0; 44 | } 45 | a{ 46 | text-decoration: none; 47 | } 48 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sheep's Toy 8 | 9 | 10 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Single deploy job since we're just deploying 25 | deploy: 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v3 33 | - run: python3 deploy.py 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v1 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v1 38 | with: 39 | path: 'dist' 40 | - name: Deploy to GitHub Pages 41 | id: deployment 42 | uses: actions/deploy-pages@main 43 | -------------------------------------------------------------------------------- /webgl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | WebGL 11 | 12 | 13 | 14 | 15 | audio-webgl 16 | audio-webgl-v2 17 | audio-webgl-v3 18 | 19 | video-webgl 20 | 21 | Digital image processing(WebGL) 22 | transform 23 | triangle 24 | 25 | 26 | 27 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /webgl/quadrangle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | webgl2 - triangle 8 | 9 | 10 |
11 | 12 |
13 | 14 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /assets/lib/sgl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * use vertexShaderSource and fragmentShaderSource to init gl 3 | * @param gl {WebGL2RenderingContext} 4 | * @param vertexShaderSource {string} 5 | * @param fragmentShaderSource {string} 6 | * @returns {WebGLProgram} 7 | */ 8 | function initShader(gl, vertexShaderSource, fragmentShaderSource) { 9 | let vertexShader = gl.createShader(gl.VERTEX_SHADER); 10 | let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); 11 | 12 | gl.shaderSource(vertexShader, vertexShaderSource) 13 | gl.shaderSource(fragmentShader, fragmentShaderSource) 14 | 15 | gl.compileShader(vertexShader); 16 | gl.compileShader(fragmentShader); 17 | 18 | let glProgram = gl.createProgram(); 19 | 20 | gl.attachShader(glProgram, vertexShader); 21 | gl.attachShader(glProgram, fragmentShader); 22 | 23 | gl.linkProgram(glProgram); 24 | 25 | gl.useProgram(glProgram); 26 | 27 | return glProgram; 28 | } 29 | 30 | /** 31 | * 32 | * @param gl {WebGL2RenderingContext} 33 | * @param glProgram {WebGLProgram} 34 | * @param bufferData {TypedArray} 35 | * @param type {GLenum} 36 | * @param attributeName {string} 37 | * @param size {number} 38 | * @param normalized {boolean} 39 | * @param drawType {GLenum} 40 | */ 41 | function setVertexAttribArray(gl, glProgram, bufferData, type, attributeName, size, normalized, drawType = gl.STATIC_DRAW) { 42 | 43 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()) 44 | gl.bufferData(gl.ARRAY_BUFFER, bufferData, drawType) 45 | 46 | let attribute = gl.getAttribLocation(glProgram, attributeName); 47 | gl.enableVertexAttribArray(attribute) 48 | gl.vertexAttribPointer(attribute, size, type, normalized, 0, 0) 49 | } 50 | 51 | 52 | /** 53 | * 54 | * @param gl {WebGL2RenderingContext} 55 | * @param glProgram {WebGLProgram} 56 | * @param image {ArrayBufferView} 57 | * @param attributeName {string} 58 | */ 59 | function setSampler2D(gl, glProgram, image, attributeName) { 60 | gl.bindTexture(gl.TEXTURE_2D, gl.createTexture()) 61 | gl.activeTexture(gl.TEXTURE0); 62 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 63 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image) 64 | let u_image = gl.getUniformLocation(glProgram, attributeName); 65 | gl.uniform1i(u_image, 0) 66 | } 67 | -------------------------------------------------------------------------------- /webgl/dip.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | original image for processing 15 | 21 | 22 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /webgl/texture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | webgl2 - triangle 8 | 9 | 10 |
11 | 12 |
13 | 14 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /webgl/triangle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | webgl2 - triangle 8 | 9 | 10 |
11 | 12 |
13 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /webgl/transform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | webgl2 - transform 8 | 9 | 10 |
11 |
If you have a keyboard you can you [WSAD] and [arrow key] to move the parallelogram.
12 | 13 |
14 | 15 | 116 | 117 | -------------------------------------------------------------------------------- /webgl/audio-webgl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Audio WebGL V1 8 | 9 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /jo/a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | What? 8 | 19 | 20 | 21 |
22 |
23 |
24 | 不能同时使用**运算和Math函数 25 | 26 | 29 | 36 | 47 | 48 | 51 | 54 | 57 | 60 |
61 | 62 | 63 |
64 |
65 | 66 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /webgl/audio-webgl-v3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Audio WebGL v3 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /webgl/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 19 | 20 | 21 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /ncmdaily/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 15 | 31 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /lastfm-export/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | LastFM-Export 18 | 19 | 20 | 21 | get 22 | 23 | Export to CSV File 24 | 25 | 26 | 27 | 28 | 29 | {{Math.ceil(finishedPages/totalPages*100)}}% 30 | ({{finishedPages}}/{{totalPages}}) 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /webgl/audio-webgl-v2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Audio WebGL v2 8 | 9 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /dip/t.js: -------------------------------------------------------------------------------- 1 | onmessage = function (msg) { 2 | console.log("Worker: Message received from main script"); 3 | console.log(msg.data); 4 | switch (msg.data[0]) { 5 | case "gaussian": 6 | postMessage(gaussian_filter(msg.data[1], msg.data[2], msg.data[3])); 7 | break; 8 | case "uniform": 9 | postMessage(uniform_filter(msg.data[1], msg.data[2])); 10 | break; 11 | case "laplace": 12 | postMessage(laplace(msg.data[1])); 13 | break; 14 | case "sobel": 15 | postMessage(sobel(msg.data[1])); 16 | break; 17 | case "min": 18 | postMessage(sortFilter(msg.data[1], "min", msg.data[2])); 19 | break; 20 | case "med": 21 | postMessage(sortFilter(msg.data[1], "med", msg.data[2])); 22 | break; 23 | case "max": 24 | postMessage(sortFilter(msg.data[1], "max", msg.data[2])); 25 | break; 26 | default: 27 | break; 28 | } 29 | console.log("Worker: Posting message back to main script"); 30 | // postMessage(workerResult); 31 | }; 32 | 33 | /** 34 | * Turn image to a grayscale image. 35 | * @param {ImageData} imageData 36 | * @returns 37 | */ 38 | function grayscale(imageData) { 39 | let newImageData = new ImageData(imageData.width, imageData.height); 40 | let data = imageData.data; 41 | let newData = newImageData.data; 42 | let length = data.length; 43 | for (let i = 0; i < length; i += 4) { 44 | let avg = (data[i] + data[i + 1] + data[i + 2]) / 3; 45 | newData[i] = avg; 46 | newData[i + 1] = avg; 47 | newData[i + 2] = avg; 48 | newData[i + 3] = data[i + 3]; 49 | } 50 | return newImageData; 51 | } 52 | /** 53 | * Invert image color. 54 | * @param {ImageData} imageData 55 | * @returns {ImageData} 56 | */ 57 | function invert(imageData) { 58 | let newImageData = new ImageData(imageData.width, imageData.height); 59 | let data = imageData.data; 60 | let newData = newImageData.data; 61 | let length = data.length; 62 | for (let i = 0; i < length; i += 4) { 63 | newData[i] = 255 - data[i]; 64 | newData[i + 1] = 255 - data[i + 1]; 65 | newData[i + 2] = 255 - data[i + 2]; 66 | newData[i + 3] = data[i + 3]; 67 | } 68 | return newImageData; 69 | } 70 | /** 71 | * Image quantification. 72 | * @param {ImageData} imageData 73 | * @param {Number} q 74 | * @returns 75 | */ 76 | function quantify(imageData, q) { 77 | let newImageData = new ImageData(imageData.width, imageData.height); 78 | let data = imageData.data; 79 | let newData = newImageData.data; 80 | let length = data.length; 81 | for (let i = 0; i < length; i += 4) { 82 | newData[i] = Math.floor(data[i] / q) * q; 83 | newData[i + 1] = Math.floor(data[i + 1] / q) * q; 84 | newData[i + 2] = Math.floor(data[i + 2] / q) * q; 85 | newData[i + 3] = data[i + 3]; 86 | } 87 | return newImageData; 88 | } 89 | /** 90 | * gaussian filter. 91 | * @param {ImageData} imageData 92 | * @param {Number} sigma the sigma of Math.E ** -(x ** 2 + y ** 2) / (2 * sigma ** 2) 93 | * @param {Number} size the size of the kernel(square). 94 | * @returns 95 | */ 96 | function gaussian_filter(imageData, sigma = 2, size = 3) { 97 | let kernel = []; 98 | let kSigma = Math.round(sigma / 2); 99 | for (let i = 0; i < size; i++) { 100 | kernel[i] = []; 101 | for (let j = 0; j < size; j++) { 102 | let x = i - kSigma; 103 | let y = j - kSigma; 104 | kernel[i][j] = Math.E ** (-(x ** 2 + y ** 2) / (2 * sigma ** 2)); 105 | } 106 | } 107 | let sum = 0; 108 | for (let i = 0; i < kernel.length; i++) { 109 | for (let j = 0; j < kernel[0].length; j++) { 110 | sum += kernel[i][j]; 111 | } 112 | } 113 | for (let i = 0; i < kernel.length; i++) { 114 | for (let j = 0; j < kernel[0].length; j++) { 115 | kernel[i][j] /= sum; 116 | } 117 | } 118 | return conv_imageData(imageData, kernel); 119 | } 120 | /** 121 | * uniform filter. 122 | * @param {ImageData} imageData 123 | * @param {Number} size the size of the kernel(square). 124 | * @returns 125 | */ 126 | function uniform_filter(imageData, size = 3) { 127 | kernel = []; 128 | let v = 1 / size / size; 129 | for (let i = 0; i < size; i++) { 130 | kernel[i] = []; 131 | for (let j = 0; j < size; j++) { 132 | kernel[i][j] = v; 133 | } 134 | } 135 | return conv_imageData(imageData, kernel); 136 | } 137 | /** 138 | * laplace. 139 | * @param {ImageData} imageData 140 | * @returns 141 | */ 142 | function laplace(imageData) { 143 | kernel = [ 144 | [0, -1, 0], 145 | [-1, 4, -1], 146 | [0, -1, 0], 147 | ]; 148 | return conv_imageData(imageData, kernel); 149 | } 150 | /** 151 | * 152 | * @param {ImageData} imageData 153 | * @param {Number} axis 154 | * @returns 155 | */ 156 | function sobel(imageData, axis = "x") { 157 | let kernel = { 158 | x: [ 159 | [-1, -2, -1], 160 | [0, 0, 0], 161 | [1, 2, 1], 162 | ], 163 | y: [ 164 | [-1, 0, 1], 165 | [-2, 0, 2], 166 | [-1, 0, 1], 167 | ], 168 | }; 169 | 170 | return conv_imageData(imageData, kernel[axis]); 171 | } 172 | /** 173 | * Image convolution. 174 | * @param {ImageData} imageData 175 | * @param {Array} kernel 2D Array 176 | */ 177 | function conv_imageData(imageData, kernel) { 178 | let newImageData = new ImageData(imageData.width, imageData.height); 179 | let data = imageData.data; 180 | let newData = newImageData.data; 181 | let iHeight = imageData.height; 182 | let iWidth = imageData.width; 183 | let kRows = kernel.length; 184 | let kCols = kernel[0].length; 185 | let kCenterX = Math.floor(kCols / 2); 186 | let kCenterY = Math.floor(kRows / 2); 187 | for (let i = 0; i < iHeight; i++) { 188 | for (let j = 0; j < iWidth; j++) { 189 | newData[(i * iWidth + j) * 4 + 3] = data[(i * iWidth + j) * 4 + 3]; 190 | let a = [0, 0, 0]; // ImageData.data is Uint8ClampedArray 191 | for (let m = 0; m < kRows; m++) { 192 | for (let n = 0; n < kCols; n++) { 193 | let ii = i + (m - kCenterY); 194 | let jj = j + (n - kCenterX); 195 | if (ii >= 0 && ii < iHeight && jj >= 0 && jj < iWidth) { 196 | a[0] += data[(ii * iWidth + jj) * 4 + 0] * kernel[m][n]; 197 | a[1] += data[(ii * iWidth + jj) * 4 + 1] * kernel[m][n]; 198 | a[2] += data[(ii * iWidth + jj) * 4 + 2] * kernel[m][n]; 199 | } 200 | } 201 | } 202 | newData[(i * iWidth + j) * 4 + 0] = a[0]; 203 | newData[(i * iWidth + j) * 4 + 1] = a[1]; 204 | newData[(i * iWidth + j) * 4 + 2] = a[2]; 205 | } 206 | } 207 | return newImageData; 208 | } 209 | /** 210 | * 211 | * @param {ImageData} imageData 212 | * @param {String} p the value of the sorted field. 213 | * @param {Number} size the size of the kernel(square). 214 | * @returns 215 | */ 216 | function sortFilter(imageData, p = "min", size = 3) { 217 | let newImageData = new ImageData(imageData.width, imageData.height); 218 | let data = imageData.data; 219 | let newData = newImageData.data; 220 | let iHeight = imageData.height; 221 | let iWidth = imageData.width; 222 | let kRows = size; 223 | let kCols = size; 224 | let kCenterX = Math.floor(size / 2); 225 | let kCenterY = Math.floor(size / 2); 226 | for (let i = 0; i < iHeight; i++) { 227 | for (let j = 0; j < iWidth; j++) { 228 | newData[(i * iWidth + j) * 4 + 3] = data[(i * iWidth + j) * 4 + 3]; 229 | let a = [[], [], []]; // ImageData.data is Uint8ClampedArray 230 | for (let m = 0; m < kRows; m++) { 231 | for (let n = 0; n < kCols; n++) { 232 | let ii = i + (m - kCenterY); 233 | let jj = j + (n - kCenterX); 234 | if (ii >= 0 && ii < iHeight && jj >= 0 && jj < iWidth) { 235 | a[0].push(data[(ii * iWidth + jj) * 4 + 0]); 236 | a[1].push(data[(ii * iWidth + jj) * 4 + 1]); 237 | a[2].push(data[(ii * iWidth + jj) * 4 + 2]); 238 | } 239 | } 240 | } 241 | a.forEach((e) => e.sort((a, b) => a - b)); 242 | let pos = 0; //最小值 243 | if (p === "max") { 244 | pos = a.length - 1; 245 | } else if (p === "med") { 246 | pos = Math.floor(a.length / 2); 247 | } else if (p === "min") { 248 | pos = 0; 249 | } 250 | newData[(i * iWidth + j) * 4 + 0] = a[0][pos]; 251 | newData[(i * iWidth + j) * 4 + 1] = a[1][pos]; 252 | newData[(i * iWidth + j) * 4 + 2] = a[2][pos]; 253 | } 254 | } 255 | return newImageData; 256 | } 257 | /** 258 | * Turn imageData to an 2D array 259 | * @param {ImageData} imageData 260 | * @returns 261 | */ 262 | function imageData2Array(imageData) { 263 | let ia = []; 264 | let iHeight = imageData.height; 265 | let iWidth = imageData.width; 266 | for (let i = 0; i < iWidth; i++) { 267 | ia[i] = []; 268 | for (let j = 0; j < iHeight; j++) { 269 | ia[i][j] = [ 270 | data[(j * iWidth + i) * 4 + 0], 271 | data[(j * iWidth + i) * 4 + 1], 272 | data[(j * iWidth + i) * 4 + 2], 273 | data[(j * iWidth + i) * 4 + 3], 274 | ]; 275 | } 276 | } 277 | return ia; 278 | } 279 | -------------------------------------------------------------------------------- /webgl/dip-webgl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 18 | 19 | 20 |
21 | Js版本 22 | 23 | original image for processing 29 | 34 |
39 |
{{kernel_name}}
40 | 41 | {{kernel}} {{kernel_name}} 42 | 43 |
44 | 50 |
51 | 52 | 53 | 54 | 55 | 279 | 280 | 281 | -------------------------------------------------------------------------------- /dip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | 20 | Digital image processing 21 | 22 | 23 | 24 | 25 | WebGL版本 26 | 27 | 36 | 58 | 59 | 60 | 66 | 71 | 72 | {{s}} 73 | 74 | 75 | 80 | 81 | 82 | 87 | 88 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 106 | 116 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 422 | 423 | 424 | --------------------------------------------------------------------------------