JavaScript - 基于 Canvas 绘制直方图

文章目录


在这里插入图片描述

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Canvas - Histogram</title>
        <style type="text/css">
            * {
                /* margin: 0;
                padding: 0; */
                box-sizing: border-box;
            }
            canvas {
                /* border-width: 1px;
                border-color: #000000;
                border-style: solid; */
            }
            .histogram {
                /* offset-x | offset-y | blur-radius | spread-radius | color */
                /* box-shadow: 0px 0px 1px 1px rgba(0, 100, 0, 0.5); */
            }
            input, label {
                cursor: pointer;
                user-select: none;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas"></canvas>
        <canvas id="histogram" class="histogram"></canvas>
        
        <div>
            <input type="radio" id="original" name="color" checked />
            <label for="original">Original</label>
            
            <br />
            
            <input type="radio" id="red-weight-method" name="color" />
            <label for="red-weight-method">Red Weight Method</label>
            <input type="radio" id="green-weight-method" name="color" />
            <label for="green-weight-method">Green Weight Method</label>
            <input type="radio" id="blue-weight-method" name="color" />
            <label for="blue-weight-method">Blue Weight Method</label>
            
            <br />
            
            <input type="radio" id="mean-value-method" name="color" />
            <label for="mean-value-method">Mean Value Method</label>
            <input type="radio" id="max-value-method" name="color" />
            <label for="max-value-method">Max Value Method</label>
            <input type="radio" id="weighted-average-method" name="color" />
            <label for="weighted-average-method">Weighted Average Method</label>
            
            <br />
            
        </div>
        
        <script type="text/javascript">
            window.onload = (event) => {
                console.log(event)
                
                main()
            }
            
            function main() {
                const canvas = document.getElementById("canvas")
                const ctx = canvas.getContext("2d")
                
                const histogram = document.getElementById("histogram")
                const histogramContext = histogram.getContext("2d")
                
                const image = new Image()
                image.onload = (event) => {
                    // console.log(event, image.width, image.height)
                    
                    canvas.width = image.width
                    canvas.height = image.height
                    
                    ctx.drawImage(image, 0, 0)
                    
                    const originalImageData = ctx.getImageData(0, 0, image.width, image.height)
                    let grayImageData = null
                    
                    const grayList = new Array(256)
                    
                    document.getElementById("original").onchange = (event) => {
                        ctx.putImageData(originalImageData, 0, 0)
                    }
                    
                    // 分量法 - 红色
                    document.getElementById("red-weight-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = originalImageData.data[i + 0] // Red Weight
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1
                        }
                        
                        ctx.putImageData(imageData, 0, 0) // 重绘
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height) // 保存灰色图像
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                    
                    // 分量法 - 绿色
                    document.getElementById("green-weight-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = originalImageData.data[i + 1] // Green Weight
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1
                        }
                        
                        ctx.putImageData(imageData, 0, 0)
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height)
                        
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                    
                    // 分量法 - 蓝色
                    document.getElementById("blue-weight-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = originalImageData.data[i + 2] // Blue Weight
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1
                        }
                        
                        ctx.putImageData(imageData, 0, 0)
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height)
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                    
                    // 平均值法
                    document.getElementById("mean-value-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = Math.round((originalImageData.data[i + 0] + originalImageData.data[i + 1] + originalImageData.data[i + 2]) / 3)
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1 // 统计灰度值数量
                        }
                        
                        ctx.putImageData(imageData, 0, 0)
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height)
                        
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                    
                    // 最大值法
                    document.getElementById("max-value-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = Math.max(originalImageData.data[i + 0], originalImageData.data[i + 1], originalImageData.data[i + 2])
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1 // 统计灰度值数量
                        }
                        
                        ctx.putImageData(imageData, 0, 0)
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height)
                        
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                    
                    // 加权平均法
                    document.getElementById("weighted-average-method").onchange = (event) => {
                        const imageData = ctx.createImageData(originalImageData)
                        
                        for (let i = 0; i < grayList.length; i++) {
                            grayList[i] = 0
                        }
                        
                        let gray = 0;
                        for (let i = 0; i < originalImageData.data.length; i += 4) {
                            gray = Math.round(0.299 * originalImageData.data[i + 0] + 0.587 * originalImageData.data[i + 1] + 0.114 * originalImageData.data[i + 2])
                            imageData.data[i + 0] = gray // Red
                            imageData.data[i + 1] = gray // Green
                            imageData.data[i + 2] = gray // Blue
                            imageData.data[i + 3] = originalImageData.data[i + 3] // Alpha
                            
                            grayList[gray] += 1 // 统计灰度值数量
                        }
                        
                        ctx.putImageData(imageData, 0, 0)
                        
                        grayImageData = ctx.getImageData(0, 0, image.width, image.height)
                        
                        
                        // 绘制直方图
                        const sum = grayList.reduce((accumulator, currentValue, index, array) => {
                            return accumulator + currentValue
                        })
                        console.log(grayList)
                        console.log("sum = " + sum, "max = " + Math.max(...grayList), "remainder = " + Math.max(...grayList) % 100)
                        histogram.width = 256 * 2
                        histogram.height = (Math.max(...grayList) + 100 - Math.max(...grayList) % 100) / 20
                        histogramContext.strokeStyle = '#000000'
                        histogramContext.lineWidth = 1
                        for (let i = 0; i < grayList.length; i++) {
                            histogramContext.beginPath()
                            histogramContext.moveTo(i * 2, histogram.height)
                            histogramContext.lineTo(i * 2, grayList[i] / 20)
                            histogramContext.stroke()
                        }
                    }
                }
                
                image.src = "img/transformers.jpg"
                
                // https://zhuanlan.zhihu.com/p/66301560
            }
        </script>
    </body>
</html>

参考

直方图,看这一篇就够了!

百度百科 - 质量分布图

百度百科 - 直方图(统计报告图)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值