Android实现二值点阵图识别
好好学习,天天向上
本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star
前言
我这几天在做一个东西,就是一张像二维码这样的 n*n 的只有两种颜色的点阵图,识别出哪个方块是深色的,哪个方块是浅色的。就像下面这张图

我一开始想的是,既然是图像识别,那不是OpenCV嘛。但是我不会呀,所以就开始研究,发现Android要使用OpenCV还涉及到JNI,NDK。算了算了好复杂,还是直接在网上找现成的轮子吧。找了一圈后,发现没有找到...既然没有轮子,那就自己造
然后想来想去,发现被自己蠢哭了,这个貌似不需要用到OpenCV吧,是我把问题想复杂了。然后开始第二种方案:比如这张图是 24*24 的,那我就把这样图缩小到24px * 24px,那不就正好一个像素对应一个格子嘛,哈哈哈。但最后还是淘汰了这个方案,因为我最终要实现的是拍照再裁切成肉眼的1:1的照片进行识别,因为肉眼裁切或者拍照的时候手机歪了一点点,很难做到正好1:1。这样的话压缩到一个格子对应一个像素这样高的精度很大可能性会造成误差。
然后方案就进化到了第三代,不去进行压缩了,直接计算出每个格子中心像素的坐标,然后判断色值就可以得到这个格子是什么颜色的了。因为不压缩的话每个格子就会占很多个像素,就算图片不是正好的1:1,也不太会出现误差。
正文
废话了一大堆,介绍完方案就来说一下具体实现吧。首先需要明确一个问题:如何去计算某个格子的中心像素的位置,用一个公式就可以得出:
(2 * n+1) * length /(2 * num)
简单解释一下:当知道一条边的长度和格子数后就可以计算出每个格子占多少个像素 length/num,求某一个格子的中心坐标,比如第10个格子,因为从0开始的。所以就是 (2*(10-1)+1) 个半个格子的长度。

先灰度图片,目的是减少误差,然后将Bitmap图片用一个二维数组表示,二维数组的每个元素的值就是对应图片中点的色值。然后通过计算每个方格中心点的坐标,将值从二维数组中取出,放入存放每个方格中心点色值的数组newPx中。最后再遍历一遍newPx,当大于某个值就说明是该方块是白色的,小于某个值则说明该方块是黑色的。那么这个某个值是多少呢,就是所有方格中心像素色值最大值与最小值的平均值。
原理介绍完了,完整代码如下:
/**
* 展示图片
* @param imagePath 图片的路径
*/
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
Bitmap greyBitmap = convertGreyImg(bitmap);
String pixels = getBitString(greyBitmap, gridNum);
picturePixels.setText(pixels);
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
/**
* 获取转化后的表示方格颜色的字符串,黑色用 ● 表示,白色用 ○ 表示
* @param img
* @param num 方格数,总方格数为num * num
* @return
*/
private String getBitString(Bitmap img, int num) {
int width = img.getWidth();//原图像宽度
int height = img.getHeight();//原图像高度
int[] oldPx = new int[width * height];//用来存储原图每个像素点的颜色信息
int[] newPx = new int[num * num]; //用来存放每个方格中心点像素颜色值
int index = 0;
img.getPixels(oldPx, 0, width, 0, 0, width, height);//获取原图中的像素信息
int[][] oldPxTwo = twoArray(oldPx,width,height); //原图每个像素点颜色信息的二维数组
int minValue = Integer.MAX_VALUE;
int maxValue = Integer.MIN_VALUE;
//循环
for (int i = 0; i < num; i++) {
int row = getCoordinate(i,width,num);
for (int j = 0; j < num; j++) {
int col = getCoordinate(j,height,num);
minValue = Math.min(minValue,oldPxTwo[row][col]);
maxValue = Math.max(maxValue,oldPxTwo[row][col]);
newPx[index++] = oldPxTwo[row][col];
}
}
StringBuilder pixels = new StringBuilder();
int middleValue = (minValue + maxValue)/2;
for (int i = 0; i < newPx.length; i++) {
if (i>0 && i%num==0) pixels.append("\n");
if (newPx[i] > middleValue) {
pixels.append("○");
} else {
pixels.append("●");
}
}
return pixels.toString();
}
/**
* 获取方块中心点 横/纵 坐标
* @param n 第几个方块,从0开始
* @param length 横向或者纵向的长度
* @param num 横向或者纵向方块数
* @return 坐标值
*/
private int getCoordinate(int n,int length,int num) {
return (2*n+1)*length /(2*num);
}
/**
* 一维数组转化为二维数组
* @param arr
* @param width 纵向的方块数,多少行
* @param height
* @return
*/
public int[][] twoArray(int[] arr,int width,int height) {
int[][] result = new int[height][width];
int k = 0;
for (int i = 0;i<height;i++) {
for (int j = 0;j<width;j++) {
result[i][j] = arr[k++];
}
}
return result;
}
/**
* 将彩色图转换为灰度图
* @param img 位图
* @return 返回转换好的位图
*/
public Bitmap convertGreyImg(Bitmap img) {
int width = img.getWidth(); //获取位图的宽
int height = img.getHeight(); //获取位图的高
int[] pixels = new int[width * height]; //通过位图的大小创建像素点数组
img.getPixels(pixels, 0, width, 0, 0, width, height);
int alpha = 0xFF << 24;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int grey = pixels[width * i + j];
int red = ((grey & 0x00FF0000) >> 16);
int green = ((grey & 0x0000FF00) >> 8);
int blue = (grey & 0x000000FF);
grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);
grey = alpha | (grey << 16) | (grey << 8) | grey;
pixels[width * i + j] = grey;
}
}
Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
result.setPixels(pixels, 0, width, 0, 0, width, height);
return result;
}
这个转化为灰度图的方法是我在网上找的。
展示一下效果:

总结
好了,到这里就介绍完了,听我介绍完是不是觉得挺简单的。因为本篇文章主要是讲如何讲如何识别点阵图,所以调用相册等内容就没有说,其实我这个Demo调用相册的代码也是直接从《第一行代码》中拿来用的,不是自己写的。代码还可以再优化一下的,比如一位数组转二维数组可以和灰度图片一起实现,不过这些就留给小伙伴们自己去实现啦!
都看完了,来个 "
赞" "赞" "赞" 鼓励一下我呗...本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star
Android实现二值点阵图识别的更多相关文章
- python图片二值化提高识别率
import cv2from PIL import Imagefrom pytesseract import pytesseractfrom PIL import ImageEnhanceimport ...
- Java 对二值化图片识别连通域
用Java 对 已经 二值化了的图片 标记连通域 每块的连通域都标记不一样的数字 public static void main(String [] args) throws IOException ...
- 自己定义View之Chart图标系列(1)——点阵图
近期要做一些图表类的需求,一開始就去github上看了看,发现开源的图表框架还是蛮多的.可是非常少有全然符合我的需求的.另外就是使用起来比較麻烦.所以就决定自己来造轮子了~~~ 今天要介绍的就是And ...
- python实现图像二值化
1.什么是图像二值化 彩色图像: 有blue,green,red三个通道,取值范围均为0-255 灰度图:只有一个通道0-255,所以一共有256种颜色 二值图像:只有两种颜色,黑色和白色,二值化就是 ...
- 最牛逼android上的图表库MpChart(二) 折线图
最牛逼android上的图表库MpChart二 折线图 MpChart折线图介绍 MpChart折线图实例 MpChart效果 最牛逼android上的图表库MpChart(二) 折线图 最近工作中, ...
- 玩转Android之二维码生成与识别
二维码,我们也称作QRCode,QR表示quick response即快速响应,在很多App中我们都能见到二维码的身影,最常见的莫过于微信了.那么今天我们就来看看怎么样在我们自己的App中集成二维码的 ...
- 机器学习进阶-案例实战-答题卡识别判 1.cv2.getPerspectiveTransform(获得投射变化后的H矩阵) 2.cv2.warpPerspective(H获得变化后的图像) 3.cv2.approxPolyDP(近似轮廓) 4.cv2.threshold(二值变化) 7.cv2.countNonezeros(非零像素点个数)6.cv2.bitwise_and(与判断)
1.H = cv2.getPerspectiveTransform(rect, transform_axes) 获得投射变化后的H矩阵 参数说明:rect表示原始的位置左上,右上,右下,左下, tra ...
- 机器学习进阶-项目实战-信用卡数字识别 1.cv2.findContour(找出轮廓) 2.cv2.boudingRect(轮廓外接矩阵位置) 3.cv2.threshold(图片二值化操作) 4.cv2.MORPH_TOPHAT(礼帽运算突出线条) 5.cv2.MORPH_CLOSE(闭运算图片内部膨胀) 6. cv2.resize(改变图像大小) 7.cv2.putText(在图片上放上文本)
7. cv2.putText(img, text, loc, text_font, font_scale, color, linestick) # 参数说明:img表示输入图片,text表示需要填写的 ...
- atitit.验证码识别step4--------图形二值化 灰度化
atitit.验证码识别step4--------图形二值化 灰度化 1. 常见二值化的方法原理总结 1 1.1. 方法一:该方法非常简单,对RGB彩色图像灰度化以后,扫描图像的每个像素值,值小于12 ...
随机推荐
- 如何解决Mybatis 日期查询时后面带.0
关于如何解决Mybatis 日期查询时后面带.0 MySQL数据库: 直接在MySQL查询语句中解决: SELECT T.ID, T.USERNAME, DATE_FORMAT(t.birthda ...
- Python3 执行JS出现JSON未定义问题
two = function(e) { var t = e.data; e.url.match(/(https?:)?(\/\/)([^/]*)/) || (e.url = "https:/ ...
- java实现高斯平滑
高斯模糊也叫作高斯平滑,这里主要用来实现图像降噪.官方有入门教程:http://opencv-java-tutorials.readthedocs.io/en/latest/ 实现代码如下: pack ...
- hdu.2042 超级楼梯
这种递归来写,除了递归我也想不到怎么写了 AC代码: #include<iostream>using namespace std;int x[41];//打表,不打表我不用想就知道过不了, ...
- Alpha阶段项目复审(小菜鸡联盟)
Alpha项目复审 小队:小菜鸡联盟 团队名称 项目名称 评价 排名 『S.L.N』 OnTime 优点:团队分工合理明确,每个成员有一定的开发经验,能用到自己较为熟悉的技术进行开发:在开发初期制定了 ...
- 访问github太慢?我写了一个开源小工具一键变快
前言 GitHub应该是广大开发者最常去的站点,这里面有大量的优秀项目,是广大开发者寻找资源,交友学习的好地方.尤其是前段时间GitHub公布了一项代码存档计划--Arctic Code Vault, ...
- Oracle - Flashback standby after resetlogs on primary
一.概述 本文将给大家介绍主库使用rman做不完全恢复后,备库如何通过flashback,继续同步 二.正式实验 本次实验采用的是oracle 11g 单实例 + oracle 11g 单实例dg 1 ...
- seo兼职顾问多少钱
http://www.wocaoseo.com/thread-199-1-1.html 随着近几年搜索引挚市场迅猛的发展,网络营销已成为企业销售的一大趋势,越来越多的企业开始投身于网络市 ...
- js中使用const声明变量时需要注意
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址(初始化的内容)不得改动.对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量. 简单 ...
- 【Android】在开发项目的时候,利用AndroidStudio开发工具,突然一直报错。
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985, QQ986945193 公众号:程序员小冰 首先说明,虽然报错,但是并不影响开发使用.但是感觉很不爽 ...