比色函数:二值化图像 - 图2

二值化图像 binarizeImage(table,number)免费

格式 : table = binarizeImage( { 范围, 颜色+偏色 }, 步数值 )
适用场景 : 文字识别/A星寻路
关联叉叉官方函数: getColorRGB
关联其他函数:ptable

  1. ![](https://cdn.nlark.com/yuque/0/2019/gif/251690/1570264607735-788aeeb6-7f99-4151-98b0-d830143914f0.gif#align=left&display=inline&height=512&originHeight=571&originWidth=1024&size=0&status=done&width=918)
  1. function binarizeImage(t,P)
  2. local P = P or 1 --[[遍历步数1像素]]
  3. local getColorRGB = getColorRGB --[[定义取色函数]]
  4. local rect = t.rect or {0,0,0,0}
  5. local diff = t.diff or {"0x000000-0x000000"}
  6. local color = {} --[[diff参数数值化]]
  7. local tab = {} --[[二值化存储]]
  8. for k,v in pairs(diff) do
  9. if color[k]==nil then
  10. local rgb_1 = tonumber(string.sub(v,1,8)) --[[参数颜色]]
  11. local rgb_2 = tonumber(string.sub(v,10,17)) --[[参数偏色]]
  12. color[k] = {
  13. lr = rgb_1/0x10000, --[[颜色rgb]]
  14. lg = rgb_1%0x10000/0x100,
  15. lb = rgb_1%0x100,
  16. sr = rgb_2/0x10000, --[[偏色rgb]]
  17. sg = rgb_2%0x10000/0x100,
  18. sb = rgb_2%0x100,
  19. }
  20. end
  21. end
  22. keepScreen(true) --[[保持屏幕,只在一张图片获取颜色]]
  23. for y=rect[2],rect[4],P do
  24. local y1 = math.floor((y - rect[2])/P) + 1 --坐标位置初始化
  25. tab[y1] = {}
  26. for x=rect[1],rect[3],P do
  27. local x1 = math.floor((x - rect[1])/P) + 1 --坐标位置初始化
  28. for i = 1,#color do --[[diff多参数循环]]
  29. local lr,lg,lb = color[i].lr,color[i].lg,color[i].lb
  30. local sr,sg,sb = color[i].sr,color[i].sg,color[i].sb
  31. local r,g,b = getColorRGB(x,y) --[[获取颜色RGB,搭配保持屏幕函数提高效率]]
  32. if math.abs(lr-r) > sr or math.abs(lg-g) > sg or math.abs(lb-b) > sb then
  33. tab[y1][x1] = 0 --[[不匹配]]
  34. else
  35. tab[y1][x1] = 1 --[[匹配]]
  36. break
  37. end
  38. end
  39. end
  40. end
  41. keepScreen(false) --[[关闭保持屏幕]]
  42. return tab
  43. end
  1. --[[小范围数据测试]]
  2. local t = {rect = {597,305,672,333},diff = {"0xf3f3f4-0x555555"}} --[[支持多颜色,但是会消耗更多比色时间]]
  3. local t = binarizeImage(t,1) -->耗时0.07
  4. ptable(t)
  1. --[[大范围数据测试]]
  2. --[[720*1280全屏单色]]
  3. local t = {rect = {0, 0, 719, 1279},diff = {"0xf3f3f4-0x555555"}}
  4. local t = binarizeImage(t,1) -->耗时3.16
  5. --[[720*1280全屏多色]]
  6. local t = {rect = {0, 0, 719, 1279},diff = {"0xf3f3f4-0x555555","0xf3f3f4-0x555555"}}
  7. local t = binarizeImage(t,1) -->耗时5

二值化7201280范围一共是921600个像素点需要运算,必要时,我们需要缩放比例来提高效率。
*缩放原理:

跳跃式遍历,当步数为2的时候,会略过1个像素点,以此类推。

  1. --[[720*1280全屏单色]]
  2. local t = {rect = {0, 0, 719, 1279},diff = {"0xf3f3f4-0x555555"}} --[[支持多颜色,耗时=颜色*n个]]
  3. local t = binarizeImage(t,2) -->耗时0.83
  4. --[[720*1280全屏多色]]
  5. local t = {rect = {0, 0, 719, 1279},diff = {"0xf3f3f4-0x555555","0xf3f3f4-0x555555"}}
  6. local t = binarizeImage(t,2) -->耗时1.4

高级:ffi.C函数

使用Lua实现二值化算法比较容易,适合新手入门学习,但是实际运用效率极低,对于后期需要全屏图像处理极不友好,此时学会思路,我们可以利用Luaffi库来调用C语言重新实现二值化算法。

  1. --binarizeImage.lua
  2. binarizeImage = function(self,tab)
  3. self.pixel_wand = self.pixel_wand or ffi.gc(lib.NewPixelWand(), lib.DestroyPixelWand)
  4. local myffi = ffi.load('binarizeImage')
  5. ffi.cdef [[
  6. int main(int *rect,int *diff,int *wand,int *pixel_wand,int (*Magick)(),double (*R)(),double (*G)(),double (*B)());
  7. int *_BINARIZE_Image;
  8. int Freememory(int*a);
  9. ]]
  10. --------------------颜色-偏色-----------------------------------------------
  11. local color={}
  12. local diff=tab.diff --颜色-偏色
  13. for k,v in pairs(diff) do
  14. local rgb_1 = tonumber(string.sub(v,1,8)) --[[参数颜色]]
  15. local rgb_2 = tonumber(string.sub(v,10,17)) --[[参数偏色]]
  16. color[k] = {
  17. rgb_1/0x10000, --[[颜色rgb]]
  18. rgb_1%0x10000/0x100,
  19. rgb_1%0x100,
  20. rgb_2/0x10000, --[[偏色rgb]]
  21. rgb_2%0x10000/0x100,
  22. rgb_2%0x100,
  23. }
  24. end
  25. local t ={}
  26. for k,v in pairs(color) do --{r,g,b,sr,sg,sb}
  27. if type(v)=="table" then
  28. local p = ffi.cast('float*', ffi.new("float[20]",v)) --指针地址
  29. table.insert(t,tonumber(p))
  30. end
  31. end
  32. local diff = ffi.new("int[10]", t) --转换成{指针地址1,指针地址2}
  33. --------------------范围-----------------------------------------------------
  34. local rect = tab.rect
  35. local rect = ffi.cast('int*', ffi.new("int[10]",rect))
  36. myffi.main(rect,diff,self.wand,self.pixel_wand,lib.MagickGetImagePixelColor,
  37. lib.PixelGetRed,lib.PixelGetGreen,lib.PixelGetBlue) --C函数计算完毕返回数组
  38. local ti={} --创建可视化二值化表,开销时间从这里开始
  39. local i=0
  40. local rect = tab.rect
  41. for y=1,rect[4]-rect[2] do
  42. ti[y]={}
  43. for x=1,rect[3]-rect[1] do
  44. ti[y][x]=0
  45. if myffi._BINARIZE_Image[i]==0 then
  46. ti[math.floor(i/(rect[3]-rect[1]))+1][x]=0
  47. else
  48. ti[math.floor(i/(rect[3]-rect[1]))+1][x]=1
  49. end
  50. i=i+1
  51. end
  52. end
  53. myffi.Freememory(myffi._BINARIZE_Image) --释放堆内存
  54. -- ptable(ti)
  55. return ti
  56. end
  1. --binarizeImage.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. /* #include <string.h> */
  5. #include <stdint.h>
  6. int *_BINARIZE_Image;
  7. int Freememory(int*a);
  8. int main(int *rect,int *diff,int *wand,int *pixel_wand,int (*Magick)(),double (*R)(),double (*G)(),double (*B)()) {
  9. _BINARIZE_Image = malloc(sizeof(int) * 5000*5000);//申请堆超大内存
  10. if(_BINARIZE_Image==NULL) {
  11. printf("申请堆内存失败\n");
  12. } else {
  13. int x,y;
  14. int j=0;
  15. for(y = 0; y<rect[3]-rect[1]; y++) { //遍历图片指定范围像素点
  16. for(x = 0; x<rect[2]-rect[0]; x++) {
  17. //---------------------获取r g b sr sg sb--------------------
  18. int i;
  19. for(i=0; i<10; i++) { //最多十个颜色
  20. if ((float *)(uintptr_t)diff[i]==NULL) {
  21. break; //如果等于nil值就退出
  22. } else {
  23. float *p =(float *)(uintptr_t)diff[i]; //获取lua表指针地址
  24. int lr=p[0]; //脚本颜色
  25. int lg=p[1];
  26. int lb=p[2];
  27. int sr=p[3]; //脚本偏色
  28. int sg=p[4];
  29. int sb=p[5];
  30. //---------------------获取当前图片r g b--------------------
  31. Magick(wand,x,y,pixel_wand);
  32. int r=R(pixel_wand)*255;
  33. int g=G(pixel_wand)*255;
  34. int b=B(pixel_wand)*255;
  35. //---------------------获取当前图片r g b--------------------
  36. if( abs(lr-r)>sr || abs(lg-g)>sg || abs(lb-b)>sb ) {
  37. _BINARIZE_Image[j]=0; //不匹配
  38. } else {
  39. _BINARIZE_Image[j]=1; //匹配
  40. break;
  41. }
  42. }
  43. }
  44. j++;
  45. //---------------------获取r g b sr sg sb--------------------
  46. }
  47. }
  48. }
  49. return 0;
  50. }
  51. int Freememory(int*a) { //释放内存
  52. free(a);
  53. a = NULL;
  54. return 0;
  55. }

3.png
3.png

  1. --调用方法:
  2. local magick=require"magick.wand"
  3. local ffi = require"ffi"
  4. local img = magick.load_image("3.png") --创建图片对象
  5. t={rect = {0, 0, 38, 55},diff={"0x000000-0x555555"}} --范围,颜色-偏色
  6. ptable(img:binarizeImage(t)) --调用binarizeImage函数

image.png

C函数经过提前编译成二进制文件来进行运算,5000*5000分辨率耗时:0.02秒,基本没什么时间消耗,但是lua要打印出上面这个表则需要创建表,开销时间很大。实际我们不需要打印表,直接用c函数去计算,效率可提高10000倍以上。

比色函数:二值化图像 - 图5献出心脏。。