美文网首页
android 彩色图片二值化转可打印的点阵黑白图

android 彩色图片二值化转可打印的点阵黑白图

作者: 艾伦oy | 来源:发表于2019-07-16 09:53 被阅读0次

    如何在手机上生成黑白图传给蓝牙设备显示出来?

    一开始我在网上找了一个转黑白图片的方法,这个方法的逻辑是 用127做临界值,来判断灰度图的灰度是否比他大,大就打白,小就打黑,代码和效果图如下

     /**
         * 转为二值图像
         *
         * @param bmp 原图bitmap
         *
         * @return
         */
        private fun convertToBMW(bmp: Bitmap, tmp:Int=130): Bitmap {
            val width = bmp.width // 获取位图的宽
            val height = bmp.height // 获取位图的高
            val pixels = IntArray(width * height) // 通过位图的大小创建像素点数组
            // 设定二值化的域值,默认值为100
            //tmp = 180;
            bmp.getPixels(pixels, 0, width, 0, 0, width, height)
            var alpha = 0xFF shl 24
            for (i in 0 until height) {
                for (j in 0 until width) {
                    val grey = pixels[width * i + j]
                    // 分离三原色
                    alpha = grey and -0x1000000 shr 24
                    var red = grey and 0x00FF0000 shr 16
                    var green = grey and 0x0000FF00 shr 8
                    var blue = grey and 0x000000FF
                    if (red > tmp) {
                        red = 255
                    } else {
                        red = 0
                    }
                    if (blue > tmp) {
                        blue = 255
                    } else {
                        blue = 0
                    }
                    if (green > tmp) {
                        green = 255
                    } else {
                        green = 0
                    }
                    pixels[width * i + j] = (alpha shl 24 or (red shl 16) or (green shl 8)
                            or blue)
                    if (pixels[width * i + j] == -1) {
                        pixels[width * i + j] = -1
                    } else {
                        pixels[width * i + j] = -16777216
                    }
                }
            }
            // 新建图片
            val newBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            // 设置图片数据
            newBmp.setPixels(pixels, 0, width, 0, 0, width, height)
            val bitmap = ThumbnailUtils.extractThumbnail(newBmp, width, height)
            imageView5.setImageBitmap(bitmap)
            return bitmap
        }
    
    黑白效果图

    这种方式有一个问题,要么一大片白色要么一大片黑色,效果不是很理想。如果打印出来根本认不出来这是谁。

    后面了解到Floyd-Steinberg算法,它是利用误差的扩散算法的Floyd-Steinberg抖动算法来对图像进行二值化处理。

    例如,灰度如的灰度值为g,误差值为e。遍历每个像素值,灰度如果大于m(127,或者像素灰度平均值,看你喜欢),那么pixels【i】=#ffffffff,打白,e=g-255;否则,打黑,pixels【i】=#ff000000,e=g;然后,这个像素点的右边,下边,和右下方的像素点,对应的加上3e/8,3e/8,e/4。最后你的到的像素数组在转成bitmap,就是抖动的单色图了。效果图如下

        //抖动算法来对图像进行二值化处理
        private fun convertGreyImgByFloyd(img: Bitmap): Bitmap {
            val width = img.width         //获取位图的宽
            val height = img.height       //获取位图的高
            val pixels = IntArray(width * height) //通过位图的大小创建像素点数组
            img.getPixels(pixels, 0, width, 0, 0, width, height)
            val gray = IntArray(height * width)
            for (i in 0 until height) {
                for (j in 0 until width) {
                    val grey = pixels[width * i + j]
                    val red = grey and 0x00FF0000 shr 16
                    gray[width * i + j] = red
                }
            }
            var e = 0
            for (i in 0 until height) {
                for (j in 0 until width) {
                    val g = gray[width * i + j]
                    if (g >= 128) {
                        pixels[width * i + j] = -0x1
                        e = g - 255
    
                    } else {
                        pixels[width * i + j] = -0x1000000
                        e = g - 0
                    }
                    if (j < width - 1 && i < height - 1) {
                        //右边像素处理
                        gray[width * i + j + 1] += 3 * e / 8
                        //下
                        gray[width * (i + 1) + j] += 3 * e / 8
                        //右下
                        gray[width * (i + 1) + j + 1] += e / 4
                    } else if (j == width - 1 && i < height - 1) {//靠右或靠下边的像素的情况
                        //下方像素处理
                        gray[width * (i + 1) + j] += 3 * e / 8
                    } else if (j < width - 1 && i == height - 1) {
                        //右边像素处理
                        gray[width * i + j + 1] += e / 4
                    }
                }
            }
            val mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
            mBitmap.setPixels(pixels, 0, width, 0, 0, width, height)
            imageView5.setImageBitmap(mBitmap)
            saveBmp(mBitmap)
            return mBitmap
        }
    
    效果图

    现在的效果达到了要求,后面可以把它转成单色图,通过传每一个像素给蓝牙设备显示出来。

    转成bmp图片,保存到手机

        /**
         * 将Bitmap存为 .bmp格式图片
         * @param bitmap
         */
        private fun saveBmp(bitmap: Bitmap?) {
            if (bitmap == null)
                return
            // 位图大小
            val nBmpWidth = bitmap.width
            val nBmpHeight = bitmap.height
            // 图像数据大小
            val bufferSize = nBmpHeight * (nBmpWidth * 3 + nBmpWidth % 4)
            try {
                // 存储文件名
                val filename = "/sdcard/test${Random.nextInt(1000)}.bmp"
                val file = File(filename)
                if (!file.exists()) {
                    file.createNewFile()
                }
                val fileos = FileOutputStream(filename)
                // bmp文件头
                val bfType = 0x4d42
                val bfSize = (14 + 40 + bufferSize).toLong()
                val bfReserved1 = 0
                val bfReserved2 = 0
                val bfOffBits = (14 + 40).toLong()
                // 保存bmp文件头
                writeWord(fileos, bfType)
                writeDword(fileos, bfSize)
                writeWord(fileos, bfReserved1)
                writeWord(fileos, bfReserved2)
                writeDword(fileos, bfOffBits)
                // bmp信息头
                val biSize = 40L
                val biWidth = nBmpWidth.toLong()
                val biHeight = nBmpHeight.toLong()
                val biPlanes = 1
                val biBitCount = 24
                val biCompression = 0L
                val biSizeImage = 0L
                val biXpelsPerMeter = 0L
                val biYPelsPerMeter = 0L
                val biClrUsed = 0L
                val biClrImportant = 0L
                // 保存bmp信息头
                writeDword(fileos, biSize)
                writeLong(fileos, biWidth)
                writeLong(fileos, biHeight)
                writeWord(fileos, biPlanes)
                writeWord(fileos, biBitCount)
                writeDword(fileos, biCompression)
                writeDword(fileos, biSizeImage)
                writeLong(fileos, biXpelsPerMeter)
                writeLong(fileos, biYPelsPerMeter)
                writeDword(fileos, biClrUsed)
                writeDword(fileos, biClrImportant)
                // 像素扫描
                val bmpData = ByteArray(bufferSize)
                val wWidth = nBmpWidth * 3 + nBmpWidth % 4
                var nCol = 0
                var nRealCol = nBmpHeight - 1
                while (nCol < nBmpHeight) {
                    run {
                        var wRow = 0
                        var wByteIdex = 0
                        while (wRow < nBmpWidth) {
                            val clr = bitmap.getPixel(wRow, nCol)
                            bmpData[nRealCol * wWidth + wByteIdex] = Color.blue(clr).toByte()
                            bmpData[nRealCol * wWidth + wByteIdex + 1] = Color.green(clr).toByte()
                            bmpData[nRealCol * wWidth + wByteIdex + 2] = Color.red(clr).toByte()
                            wRow++
                            wByteIdex += 3
                        }
                    }
                    ++nCol
                    --nRealCol
                }
    
                fileos.write(bmpData)
                fileos.flush()
                fileos.close()
    
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            }
    
        }
    
        @Throws(IOException::class)
        protected fun writeWord(stream: FileOutputStream, value: Int) {
            val b = ByteArray(2)
            b[0] = (value and 0xff).toByte()
            b[1] = (value shr 8 and 0xff).toByte()
            stream.write(b)
        }
    
        @Throws(IOException::class)
        protected fun writeDword(stream: FileOutputStream, value: Long) {
            val b = ByteArray(4)
            b[0] = (value and 0xff).toByte()
            b[1] = (value shr 8 and 0xff).toByte()
            b[2] = (value shr 16 and 0xff).toByte()
            b[3] = (value shr 24 and 0xff).toByte()
            stream.write(b)
        }
    
        @Throws(IOException::class)
        protected fun writeLong(stream: FileOutputStream, value: Long) {
            val b = ByteArray(4)
            b[0] = (value and 0xff).toByte()
            b[1] = (value shr 8 and 0xff).toByte()
            b[2] = (value shr 16 and 0xff).toByte()
            b[3] = (value shr 24 and 0xff).toByte()
            stream.write(b)
        }
    
    

    End!

    相关文章

      网友评论

          本文标题:android 彩色图片二值化转可打印的点阵黑白图

          本文链接:https://www.haomeiwen.com/subject/crxzkctx.html