链接1:利用卷积神经网络识别骰子点数

链接1:利用神经网络识别骰子点数

前言

前段时间借用神经网络和卷积神经网络实现了骰子点数的识别,但是一个很严重的问题一直困扰我,那就是当两个骰子叠在一起的时候,将两个骰子分开并不是一件简单的事情。

下图是我在识别过程中产生的不能识别的,叠加在一起的图片素材。

面对这些形态各异的图片,有的时候是两个骰子一个角连在一起,有的是一条边,有的是三个骰子叠在一起。所以,很难找到一个满意的办法解决这个问题。

第一思路就是从原始的RGB图像着手,通过调整二值化阈值,希望能够将骰子对象分割开来,但是遗憾的是我试了好几种方法,都是不行的,原因在于原图像在交接的地方本来就很模糊,颜色变化很小,所以使用二值化阈值调整很难得到完美的解决方案。

期间我尝试了不同的方法

1. 分水岭

[java]  view plain copy
  1. close all
  2. clc
  3. figure(1)
  4. subplot(231)
  5. RGB_img=imread('161220S010129.jpg');
  6. imgsize =size(RGB_img);
  7. RGB_img = imcrop(RGB_img,[imgsize(1,2)*0.418 imgsize(1,1)*0.655 215 134]);%大部分图像布局固定
  8. imshow(RGB_img)
  9. %%
  10. subplot(232)
  11. %imhist(A(:,:,1));
  12. bw=im2bw(rgb2gray(RGB_img));
  13. bw=medfilt2(bw);
  14. planes=bwareaopen(bw,100);
  15. imshow(planes)
  16. %%
  17. subplot(233)
  18. D=bwdist(imcomplement(planes));
  19. D=mat2gray(D);
  20. imshow(D)
  21. figure
  22. subimage(D)
  23. hold on
  24. [C,h]=imcontour(D,0.2:0.2:0.8);
  25. set(h,'ShowText','on','TextStep',get(h,'LevelStep')*2)
  26. text_handle = clabel(C,h,'color','g');
  27. figure(1)
  28. %%
  29. subplot(234)
  30. M=imimposemin(imcomplement(D),D>.8);
  31. imshow(M);
  32. %%
  33. subplot(236)
  34. L=watershed(M);
  35. r=L & planes;
  36. imshow(r)
  37. %%%%%%%%%%%%
  38. stats=regionprops(r,'BoundingBox','Centroid');
  39. hold on
  40. c=cat(1,stats.Centroid);
  41. plot(c(:,1),c(:,2),'r*')
  42. bb={stats.BoundingBox};
  43. cellfun(@(x) rectangle('Position',x,'EdgeColor','y'),bb)
  44. %%
  45. subplot(235)
  46. L(r)=5;
  47. imshow(L,[])

2. 抽取局部再二值化寻找连通区域

[java]  view plain copy
  1. close all;
  2. RGB_img=imread('161221S010029.jpg');
  3. imgsize =size(RGB_img);
  4. RGB_img = imcrop(RGB_img,[imgsize(1,2)*0.418 imgsize(1,1)*0.655 215 134]);%大部分图像布局固定
  5. GRY_img=rgb2gray(RGB_img);
  6. level = graythresh(GRY_img);
  7. BW_img=im2bw(GRY_img,0.7);
  8. BW_img =imclearborder(BW_img,8);
  9. [img1,map] = rgb2ind(RGB_img,64);            %# Create your quantized image
  10. rPlane = reshape(map(img1+1,1),size(img1));  %# Red color plane for image
  11. gPlane = reshape(map(img1+1,2),size(img1));  %# Green color plane for image
  12. bPlane = reshape(map(img1+1,3),size(img1));  %# Blue color plane for image
  13. figure('units', 'normalized', 'position', [0 0 1 1]);
  14. subplot(2, 2, 1); imshow(rPlane, []); title('R');
  15. subplot(2, 2, 2); imshow(gPlane, []); title('G');
  16. subplot(2, 2, 3); imshow(bPlane, []); title('B');
  17. subplot(2, 2, 4); imshow(GRY_img, []); title('O');
  18. figure('units', 'normalized', 'position', [0 0 1 1]);
  19. I2 =  bwareaopen(BW_img,100,8);%删除二值图像BW中面积小于P的对象,默认情况下使用8邻域。
  20. cc = bwconncomp(I2,8);%bwconnecomp()是找出二值图像中连通的区域, CC返回结果,比如这样一幅图(简化便于理解):
  21. n=cc.NumObjects;%有多少个对象
  22. k = regionprops(cc,'Area','Perimeter','MajorAxisLength','MinorAxisLength','Image');%用途是get the properties of region,即用来度量图像区域属性的函数。
  23. subplot(2, 2, 1); imshow(BW_img, []); title('O');
  24. subplot(2, 2, 2); imshow(I2, []); title('G');
  25. [m,n] = find(I2==1);
  26. max_x=max(m);
  27. max_y=max(n);
  28. min_x=min(m);
  29. min_y=min(n);
  30. new_img=RGB_img(min_x:max_x,min_y:max_y,:);
  31. subplot(2, 2,3); imshow(new_img, []); title('G');
  32. new_BW_img=im2bw(new_img,0.7);
  33. subplot(2, 2,4); imshow(new_BW_img, []); title('new_BW_img');
  34. %figure('units', 'normalized', 'position', [0 0 1 1]);
  35. for i=1:n
  36. % subplot(2, 2, i); imshow(k(i).Image, []); title('T');
  37. end

3. K-means 分类

[java]  view plain copy
  1. close all;
  2. clear all;
  3. clc;
  4. C_Segments=3;
  5. img_original=imread('161224S011389.jpg');
  6. imgsize =size(img_original);
  7. img_original = imcrop(img_original,[imgsize(1,2)*0.418 imgsize(1,1)*0.655 215 134]);%大部分图像布局固定
  8. figure,imshow(img_original),title('原始图像');    %显示原图像
  9. img_gray=rgb2gray(img_original);
  10. figure,imshow(img_gray),title('原始灰度图像');
  11. % 获取图像的长宽
  12. [m,n]=size(img_gray);
  13. % 灰度阈值计算
  14. T=graythresh(img_gray);
  15. img_bw=im2bw(img_gray,T);
  16. figure,imshow(img_bw),title('原始二值图像');
  17. % 将图像进行RGB——3通道分解
  18. A = reshape(img_original(:, :, 1), m*n, 1);    % 将RGB分量各转为kmeans使用的数据格式n行,一样一样本
  19. B = reshape(img_original(:, :, 2), m*n, 1);
  20. C = reshape(img_original(:, :, 3), m*n, 1);
  21. dat = [A B C];  % r g b分量组成样本的特征,每个样本有三个属性值,共width*height个样本
  22. cRGB = kmeans(double(dat), C_Segments,...
  23. 'Distance','city',...
  24. 'emptyaction','singleton',...
  25. 'start','sample');    % 使用聚类算法分为2类
  26. rRGB = reshape(cRGB, m, n);     % 反向转化为图片形式
  27. figure, imshow(label2rgb(rRGB)),title('RGB通道分割结果');   % 显示分割结果
  28. % 将图像进行单一通道灰度分解
  29. GraySeg= reshape(img_gray(:, :), m*n, 1);
  30. cGray=kmeans(double(GraySeg), 2);
  31. rGray= reshape(cGray, m, n);     % 反向转化为图片形式
  32. figure, imshow(label2rgb(rGray)),title('灰度通道分割结果');   % 显示分割结果

4.sobel 算子和watershed 这个是MATLAB官方示例

[java]  view plain copy
  1. clc; clear all; close all;
  2. %第一步:读入彩色图像,将其转化成灰度图像
  3. rgb = imread('abc.jpg');
  4. if ndims(rgb) == 3
  5. I = rgb2gray(rgb);
  6. else
  7. I = rgb;
  8. end
  9. figure('units', 'normalized', 'position', [0 0 1 1]);
  10. subplot(1, 2, 1); imshow(rgb); title('原图');
  11. subplot(1, 2, 2); imshow(I); title('灰度图');
  12. %第2步:将梯度幅值作为分割函数
  13. %使用Sobel边缘算子对图像进行水平和垂直方向的滤波,然后求取模值,sobel算子滤波后的图像在边界处会显示比较大的值,在没有边界处的值会很小。
  14. hy = fspecial('sobel');%fspecial函数用于建立预定义的滤波算子
  15. hx = hy';
  16. Iy = imfilter(double(I), hy, 'replicate');%实现线性空间滤波函数。功能:对任意类型数组或多维图像进行滤波
  17. Ix = imfilter(double(I), hx, 'replicate');
  18. gradmag = sqrt(Ix.^2 + Iy.^2);
  19. figure('units', 'normalized', 'position', [0 0 1 1]);
  20. subplot(1, 2, 1); imshow(I,[]), title('灰度图像')
  21. subplot(1, 2, 2); imshow(gradmag,[]), title('梯度幅值图像')
  22. %%第2步:标记前景对象
  23. % 有多种方法可以应用在这里来获得前景标记,这些标记必须是前景对象内部的连接斑点像素。
  24. % 这个例子中,将使用形态学技术“基于开的重建”和“基于闭的重建”来清理图像。
  25. % 这些操作将会在每个对象内部创建单位极大值,使得可以使用imregionalmax来定位。
  26. %
  27. % 开运算和闭运算:先腐蚀后膨胀称为开;先膨胀后腐蚀称为闭。开和闭这两种运算可以除去比结构元素小的特定图像细节,
  28. % 同时保证不产生全局几何失真。开运算可以把比结构元素小的突刺滤掉,切断细长搭接而起到分离作用;
  29. % 闭运算可以把比结构元素小的缺口或孔填充上,搭接短的间隔而起到连接作用。
  30. %开操作是腐蚀后膨胀,基于开的重建(基于重建的开操作)是腐蚀后进行形态学重建。下面比较这两种方式。
  31. %% 首先,用imopen做开操作。
  32. se = strel('disk', 2);%结构元素,用于膨胀腐蚀及开闭运算等操作的结构元素对象具体用法:SE=strel(shape,parameters)创建由指定形状shape对应的结构元素。
  33. Io = imopen(I, se);%开操作是一般使对象的轮廓变得光滑,断开狭窄的间断和消除细的突出物
  34. figure('units', 'normalized', 'position', [0 0 1 1]);
  35. subplot(1, 2, 1); imshow(I, []); title('灰度图像');
  36. subplot(1, 2, 2); imshow(Io), title('图像开操作')
  37. %% 接下来,通过腐蚀后重建来做基于开的重建计算。
  38. Ie = imerode(I, se);
  39. Iobr = imreconstruct(Ie, I);
  40. figure('units', 'normalized', 'position', [0 0 1 1]);
  41. subplot(1, 2, 1); imshow(I, []); title('灰度图像');
  42. subplot(1, 2, 2); imshow(Iobr, []), title('基于开的重建图像')
  43. %% 开操作后,接着进行闭操作,可以移除较暗的斑点和枝干标记。对比常规的形态学闭操作和基于闭的重建操作。首先,使用imclose:
  44. Ioc = imclose(Io, se);
  45. Ic = imclose(I, se);
  46. figure('units', 'normalized', 'position', [0 0 1 1]);
  47. subplot(2, 2, 1); imshow(I, []); title('灰度图像');
  48. subplot(2, 2, 2); imshow(Io, []); title('开操作图像');
  49. subplot(2, 2, 3); imshow(Ic, []); title('闭操作图像');
  50. subplot(2, 2, 4); imshow(Ioc, []), title('开闭操作');
  51. %现在使用imdilate,然后使用imreconstruct。注意必须对输入图像求补,对imreconstruct输出图像求补。
  52. %IM2 = imcomplement(IM)计算图像IM的补集。IM可以是二值图像,或者RGB图像。IM2与IM有着相同的数据类型和大小。
  53. Iobrd = imdilate(Iobr, se);%利用结构元素se膨胀
  54. Iobrcbr = imreconstruct(imcomplement(Iobrd), imcomplement(Iobr));
  55. Iobrcbr = imcomplement(Iobrcbr);
  56. figure('units', 'normalized', 'position', [0 0 1 1]);
  57. subplot(2, 2, 1); imshow(I, []); title('灰度图像');
  58. subplot(2, 2, 2); imshow(Ioc, []); title('开闭操作');
  59. subplot(2, 2, 3); imshow(Iobr, []); title('基于开的重建图像');
  60. subplot(2, 2, 4); imshow(Iobrcbr, []), title('基于闭的重建图像');
  61. %通过比较Iobrcbr和loc可以看到,在移除小污点同时不影响对象全局形状的应用下,基于重建的开闭操作要比标准的开闭重建更加有效。
  62. %计算Iobrcbr的局部极大来得到更好的前景标记。
  63. fgm = imregionalmax(Iobrcbr);
  64. figure('units', 'normalized', 'position', [0 0 1 1]);
  65. subplot(1, 3, 1); imshow(I, []); title('灰度图像');
  66. subplot(1, 3, 2); imshow(Iobrcbr, []); title('基于重建的开闭操作');
  67. subplot(1, 3, 3); imshow(fgm, []); title('局部极大图像');
  68. %为了帮助理解这个结果,叠加前景标记到原图上。
  69. It1 = rgb(:, :, 1);
  70. It2 = rgb(:, :, 2);
  71. It3 = rgb(:, :, 3);
  72. It1(fgm) = 255; It2(fgm) = 0; It3(fgm) = 0;
  73. I2 = cat(3, It1, It2, It3);
  74. figure('units', 'normalized', 'position', [0 0 1 1]);
  75. subplot(2, 2, 1); imshow(rgb, []); title('原图像');
  76. subplot(2, 2, 2); imshow(Iobrcbr, []); title('基于重建的开闭操作');
  77. subplot(2, 2, 3); imshow(fgm, []); title('局部极大图像');
  78. subplot(2, 2, 4); imshow(I2); title('局部极大叠加到原图像');
  79. %% 注意到大多闭塞处和阴影对象没有被标记,这就意味着这些对象在结果中将不会得到合理的分割。
  80. %而且,一些对象的前景标记会一直到对象的边缘。这就意味着应该清理标记斑点的边缘,然后收缩它们。可以通过闭操作和腐蚀操作来完成。
  81. se2 = strel(ones(5,5));
  82. fgm2 = imclose(fgm, se2);
  83. fgm3 = imerode(fgm2, se2);
  84. figure('units', 'normalized', 'position', [0 0 1 1]);
  85. subplot(2, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
  86. subplot(2, 2, 2); imshow(fgm, []); title('局部极大图像');
  87. subplot(2, 2, 3); imshow(fgm2, []); title('闭操作');
  88. subplot(2, 2, 4); imshow(fgm3, []); title('腐蚀操作');
  89. %% 这个过程将会留下一些偏离的孤立像素,应该移除它们。
  90. %可以使用bwareaopen,用来移除少于特定像素个数的斑点。BW2 = bwareaopen(BW,P)从二值图像中移除所以少于P像素值的连通块,得到另外的二值图像BW2。
  91. fgm4 = bwareaopen(fgm3, 20);
  92. It1 = rgb(:, :, 1);
  93. It2 = rgb(:, :, 2);
  94. It3 = rgb(:, :, 3);
  95. It1(fgm4) = 255; It2(fgm4) = 0; It3(fgm4) = 0;
  96. I3 = cat(3, It1, It2, It3);
  97. figure('units', 'normalized', 'position', [0 0 1 1]);
  98. subplot(2, 2, 1); imshow(I2, []); title('局部极大叠加到原图像');
  99. subplot(2, 2, 2); imshow(fgm3, []); title('闭腐蚀操作');
  100. subplot(2, 2, 3); imshow(fgm4, []); title('去除小斑点操作');
  101. subplot(2, 2, 4); imshow(I3, []); title('修改局部极大叠加到原图像');
  102. %% 第4步:计算背景标记
  103. %现在,需要标记背景。在清理后的图像Iobrcbr中,暗像素属于背景,所以可以从阈值操作开始。
  104. bw = im2bw(Iobrcbr, graythresh(Iobrcbr));
  105. figure('units', 'normalized', 'position', [0 0 1 1]);
  106. subplot(1, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
  107. subplot(1, 2, 2); imshow(bw, []); title('阈值分割');
  108. %%背景像素在黑色区域,但是理想情形下,不必要求背景标记太接近于要分割的对象边缘。
  109. %%通过计算“骨架影响范围”来“细化”背景,或者SKIZ,bw的前景。这个可以通过计算bw的距离变换的分水岭变换来实现,然后寻找结果的分水岭脊线(DL==0)。
  110. %%D=bwdist(BW)计算二值图像BW的欧几里得矩阵。对BW的每一个像素,距离变换指定像素和最近的BW非零像素的距离。
  111. %%bwdist默认使用欧几里得距离公式。BW可以由任意维数,D与BW有同样的大小。
  112. D = bwdist(bw);
  113. DL = watershed(D);
  114. bgm = DL == 0;
  115. figure('units', 'normalized', 'position', [0 0 1 1]);
  116. subplot(2, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
  117. subplot(2, 2, 2); imshow(bw, []); title('阈值分割');
  118. subplot(2, 2, 3); imshow(label2rgb(DL), []); title('分水岭变换示意图');
  119. subplot(2, 2, 4); imshow(bgm, []); title('分水岭变换脊线图');
  120. %% 第5步:计算分割函数的分水岭变换
  121. gradmag2 = imimposemin(gradmag, bgm | fgm4);
  122. figure('units', 'normalized', 'position', [0 0 1 1]);
  123. subplot(2, 2, 1); imshow(bgm, []); title('分水岭变换脊线图');
  124. subplot(2, 2, 2); imshow(fgm4, []); title('前景标记');
  125. subplot(2, 2, 3); imshow(gradmag, []); title('梯度幅值图像');
  126. subplot(2, 2, 4); imshow(gradmag2, []); title('修改梯度幅值图像');
  127. %% 最后,可以做基于分水岭的图像分割计算。第6步:查看结果
  128. It1 = rgb(:, :, 1);
  129. It2 = rgb(:, :, 2);
  130. It3 = rgb(:, :, 3);
  131. fgm5 = imdilate(L == 0, ones(3, 3)) | bgm | fgm4;
  132. It1(fgm5) = 255; It2(fgm5) = 0; It3(fgm5) = 0;
  133. I4 = cat(3, It1, It2, It3);
  134. figure('units', 'normalized', 'position', [0 0 1 1]);
  135. subplot(1, 2, 1); imshow(rgb, []); title('原图像');
  136. subplot(1, 2, 2); imshow(I4, []); title('标记和对象边缘叠加到原图像');

以上四种方法,虽然都只是浅尝辄止,但是处理我遇到的问题,利用最现成的方法,都不能够有很好的效果。我期望的是,有没有现成的,可以直接用到的方法呢?找了很久找不到。我又是新手,对图像处理完全不懂,最近才入行,想了好久,我想出了另外一种方法,我把它叫做旋转切割法。

旋转切割法

这个方法对于只有两个骰子连在一起的图片可以很好的分割开来。原理其实很简单。我介绍一下怎么来的。

最开始,我对没有分割开的骰子进行了细致的总结分析,发现两个骰子连在一起的图片基本上都有一个中心点,中心点基本上都在图片的中央位置。如果我以这个中心点为端点,引一条直线,旋转360度扫描每一个角度,如果那个角度上面黑色像素比重最大,那么证明我应该沿着这条线切割。然后找另外一条同样的线,只不过要夹角大于90度。

想法很美好,但是实现之后发现不行。因为图片作为一个矩阵,坐标只可能是整数,在某些角度,你会在分割的线上找不到任何像素。这种情况还比较多。

请看代码:

[java]  view plain copy
  1. clear all;close all;
  2. img=imread('stackdice/161221S011172.jpg-1.jpg');
  3. img=im2bw(img);
  4. figure;imshow(img,[]);
  5. s_x=1;
  6. s_y=1;
  7. [m,n] = size(img);
  8. d=ceil(sqrt(m^2+n^2));%直径
  9. new_matrix = zeros(d,d);
  10. T2 = [1,0,0;0,1,0;-m/2,-n/2,1];  %x、y轴平移值原点
  11. T3 = [1,0,0;0,1,0;m/2,n/2,1];    %x、y轴反平移
  12. T4 = [1,0,0;0,1,0;-(d/2+m),-(d/2+n),1];    %x、y轴反平移
  13. T5 = [1,0,0;0,1,0;(d-m)/2,(d-n)/2,1];    %x、y轴反平移
  14. T1 = [s_x,0,0;0,s_y,0;0,0,1];   %对应的比例系数矩阵
  15. %T = T2*T1*T3;     %P_new = P_old*T2*T1*T3  顺序不能错了
  16. T = T4*T5;     %P_new = P_old*T2*T1*T3  顺序不能错了
  17. for i=1:d
  18. for j=1:d
  19. p = floor([i,j,1]*T5^-1);%由P_new = P_old*T 可得:P_old = P_new*(T^-1)
  20. if (p(1)<=m)&&(p(1)>0)&&(p(2)<=n)&&(p(2)>0) %限制范围
  21. new_matrix(i,j) = img(p(1),p(2));   %坐标变换关系
  22. else
  23. new_matrix(i,j) = 0;     %没有的点赋值为0
  24. end
  25. end
  26. end
  27. %%以上获取新的图片 图片周围加了一圈
  28. center_x=d/2;
  29. center_y=d/2;%中心坐标
  30. figure;imshow(new_matrix,[]);
  31. hold on;
  32. pointGroup=[center_x center_y;d d/2];% 初始位置
  33. angleGroup=(0:pi/4:2*pi);
  34. init_line_value = cell(d/2);
  35. for i=1:length(angleGroup)
  36. theat=angleGroup(i);
  37. pointGroup(2,1)=ceil((cos(theat)+1)*d/2);
  38. pointGroup(2,2)=ceil((sin(theat)+1)*d/2);
  39. plot(pointGroup(:,1),pointGroup(:,2),'.-','Color',[(0.7+0.1/i)^2 1-(0.05*i) 0.5/i^2]);
  40. if pointGroup(2,1)==0
  41. pointGroup(2,1)=1
  42. end
  43. if pointGroup(2,2)==0
  44. pointGroup(2,2)=1
  45. end
  46. pointGroup
  47. A=pointGroup(1,:);%A 点
  48. B=pointGroup(2,:);
  49. if B(1)-A(1)==0
  50. if A(2)-B(2)>0
  51. tmpl= new_matrix(A(1),B(2):A(2));
  52. init_line_value{i,1:length(tmpl)}=tmpl;
  53. else
  54. tmpl=  new_matrix(A(1),B(2):A(2));
  55. init_line_value{i,1:length(tmpl)}= new_matrix(A(1),A(2):B(2));
  56. end
  57. continue;
  58. end
  59. if B(2)-A(2)==0
  60. if A(1)-B(1)<0
  61. tmpl= new_matrix(A(1):B(1),A(1));
  62. init_line_value{i,1:length(tmpl)}=tmpl;
  63. else
  64. tmpl= new_matrix(B(1):A(1),A(1));
  65. init_line_value{i,1:length(tmpl)}=tmpl;
  66. end
  67. continue;
  68. end
  69. k=(B(2)-A(2))/(B(1)-A(1)); %k是系数;
  70. b=A(2)-k*A(1);%b是常数。(方程:y=k*x+b)。
  71. %旋转的四种情况
  72. if pointGroup(2,1)>=d/2 && pointGroup(2,2)>=d/2
  73. kkaa=1;
  74. for kk1=d/2:pointGroup(2,1)
  75. init_line_value{i,kkaa}=new_matrix(kk1,ceil(k*kk1+b));
  76. kkaa=kkaa+1;
  77. end
  78. end
  79. if pointGroup(2,1)<d/2 && pointGroup(2,2)>d/2
  80. kkaa=1;
  81. for kk1=pointGroup(2,1):d/2
  82. init_line_value{i,kkaa}=new_matrix(kk1,ceil(k*kk1+b));
  83. kkaa=kkaa+1;
  84. end
  85. end
  86. if pointGroup(2,1)>d/2 && pointGroup(2,2)<d/2
  87. kkaa=1;
  88. for kk1=d/2:pointGroup(2,1)
  89. init_line_value{i,kkaa}=new_matrix(kk1,ceil(k*kk1+b));
  90. kkaa=kkaa+1;
  91. end
  92. end
  93. if pointGroup(2,1)<d/2 && pointGroup(2,2)<d/2
  94. kkaa=1;
  95. for kk1=pointGroup(2,1):d/2
  96. init_line_value{i,kkaa}=new_matrix(kk1,ceil(k*kk1+b));
  97. kkaa=kkaa+1;
  98. end
  99. end
  100. end

那么,既然选择线不行,就只能旋转整个图像了。为什么我会首先考虑线呢?矩阵旋转和向量旋转,自然是向量运算量小很多。果不其然,换为整个图片旋转,然后固定在水平位置采样之后,执行时间慢了好多。

[java]  view plain copy
  1. clear all;close all;
  2. img=imread('stackdice/161221S011161.jpg-2.jpg');
  3. img=im2bw(img);
  4. s_x=1;
  5. s_y=1;
  6. [m,n] = size(img);
  7. d=ceil(floor(sqrt(m^2+n^2)));%直径
  8. if mod(d,2)~=0
  9. d=d+1;
  10. end
  11. new_matrix = zeros(d,d);
  12. T2 = [1,0,0;0,1,0;-m/2,-n/2,1];  %x、y轴平移值原点
  13. T3 = [1,0,0;0,1,0;m/2,n/2,1];    %x、y轴反平移
  14. T4 = [1,0,0;0,1,0;-(d/2+m),-(d/2+n),1];    %x、y轴反平移
  15. T5 = [1,0,0;0,1,0;(d-m)/2,(d-n)/2,1];    %x、y轴反平移
  16. T1 = [s_x,0,0;0,s_y,0;0,0,1];   %对应的比例系数矩阵
  17. %T = T2*T1*T3;     %P_new = P_old*T2*T1*T3  顺序不能错了
  18. T = T4*T5;     %P_new = P_old*T2*T1*T3  顺序不能错了
  19. for i=1:d
  20. for j=1:d
  21. p = floor([i,j,1]*T5^-1);%由P_new = P_old*T 可得:P_old = P_new*(T^-1)
  22. if (p(1)<=m)&&(p(1)>0)&&(p(2)<=n)&&(p(2)>0) %限制范围
  23. new_matrix(i,j) = img(p(1),p(2));   %坐标变换关系
  24. else
  25. new_matrix(i,j) = 0;     %没有的点赋值为0
  26. end
  27. end
  28. end
  29. %%以上获取新的图片 图片周围加了一圈
  30. center_x=d/2;
  31. center_y=d/2;%中心坐标
  32. figure;imshow(new_matrix,[]);
  33. hold on;
  34. pointGroup=[center_x center_y;d d/2];% 初始位置
  35. angleGroup=(0:pi/4:2*pi);
  36. for i=1:length(angleGroup)
  37. theat=angleGroup(i);
  38. pointGroup(2,1)=ceil((cos(theat)+1)*d/2);
  39. pointGroup(2,2)=ceil((sin(theat)+1)*d/2);
  40. plot(pointGroup(:,1),pointGroup(:,2),'.-','Color',[(0.7+0.1/i)^2 1-(0.05*i) 0.5/i^2]);
  41. end
  42. for i222=1:length(angleGroup)
  43. theat=angleGroup(i222);
  44. newroate= RotateFunction(new_matrix,theat);
  45. x1_pix(:,:,i222)=newroate(d/2,d/2:d);
  46. x2_pix(:,:,i222)=newroate(d/2,1:d/2);
  47. end
  48. max=0;
  49. max_index=0;
  50. for i=1:length(x1_pix(1,1,:))
  51. tmp= length(find(x1_pix(:,:,i)==0));
  52. tmp_rate = tmp/length(x1_pix(:,:,i));
  53. if tmp_rate>max
  54. max=tmp_rate;
  55. max_index=angleGroup(i);
  56. end
  57. end
  58. for i=1:length(x2_pix(1,1,:))
  59. tmp= length(find(x2_pix(:,:,i)==0));
  60. tmp_rate = tmp/length(x2_pix(:,:,i));
  61. if tmp_rate>max
  62. max=tmp_rate;
  63. max_index=angleGroup(i);
  64. end
  65. end
  66. newroate_final= RotateFunction(new_matrix,max_index);
  67. img1=newroate_final(1:d/2,1:d);
  68. img2=newroate_final(d/2:d,1:d);
  69. figure;imshow(img1,[]);
  70. figure;imshow(img2,[]);

无论怎样,先将就用一下把。对于三个骰子连在一起的我暂时还没有好的方法。但是目前看来,我的设计足够我们在正式的生产环境中使用了。

下图就是我通过这种方法分割的效果:

总结:

总的来说,试了很多很多方法,也许对其他的算法了解不深入,所以没有很好的结果,但是,最适合的,就是最好的。

骰子点数识别之图像分割相关推荐

  1. python骰子点数识别_Python n个骰子的点数

    用两个数组来存储骰子点数的每一个总数出现次数.在一次循环中,第一个数组中的第n个数字表示骰子和为n出现的次数.在下一次循环中加入一个新的骰子,此时和为n的骰子出现的次数应该等于上一次循环中骰子点数和为 ...

  2. Tutorial教程:利用神经网络识别骰子点数(1)

    前言小叙 机器学习,Machine Learning走进我的视野范围,过程还挺有意思.第一次听到这个词还是在Blacksburg的公寓,王俊鹏向我介绍了计算机研究领域的几大方向,其中就有机器学习,人工 ...

  3. Tutorial教程:利用卷积神经网络识别骰子点数(2)

    承接上文 利用神经网络识别骰子点数 前言小叙 前一段时间通过bpnn反向传播神经网络实现了识别骰子点数的目标,而且效果不错,我们的识别率可以达到80%上下,其实已经可以应用于生产环境了.只不过读了卷积 ...

  4. n 个骰子点数和及各自出现的概率

    题目: 把 n 个骰子扔在地上,所有骰子朝上一面的点数之和为 S.输入 n,打印出S的所有可能的值出现的概率. 这道算法题可采取动态规划法来求解.鉴于<剑指Offer>中对该题的解法晦涩难 ...

  5. 基于人脸识别和图像分割技术制作证件照

    我们经常会遇到这样的问题,报名参加考某种考试, 需要提交符合指定背景.尺寸要求的照片,但是手上只有生活中,或者照片尺寸符合要求,但是背景不符合要求的情况. 今天我教大家基于人脸识别和图像分割技术制作证 ...

  6. 动态hook微信,随意控制猜拳和骰子点数

    为什么80%的码农都做不了架构师?>>>    大家知道,微信聊天里可以玩猜拳和骰子点数,那么要是可以随意控制游戏的结果,是不是更有趣呢?下面就为大家奉上这个刚刚新鲜出炉的插件. 大 ...

  7. 3446. 骰子点数之和问题 动态规划

    3446. 骰子点数之和问题 剑指 Offer 60. n个骰子的点数 逆推: #include<bits/stdc++.h> using namespace std; const int ...

  8. 三个骰子点数之和概率

    题目出自美团点评在线笔试题,求三个骰子的点数之和概率最大的是? 思路:三个骰子点数之和的范围是3~18,越靠近两边出现的概率越小,因此点数和概率最大的情况应该出现在中间位置.计算中间9,10,11,1 ...

  9. Python:利用模拟方法计算骰子点数出现的概率

      运用模拟方法模拟投掷两个骰子(分别用随机变量x和y表示)10000次,计算出下列情况出现的概率: (1)两个骰子点数和为"小"(小于7): (2)两个骰子点数和为"大 ...

最新文章

  1. PHP- 深入PHP、Redis连接
  2. Intel x86架构之多处理器与APIC
  3. Java私有变量是否可继承
  4. junit runner_了解JUnit的Runner架构
  5. 753 Cracking the Safe
  6. php中的file_upload,PHP文件上传(PHP file upload)
  7. python-json模块
  8. 在vSphere 6.x vSAN数据存储上使用Oracle RAC(2121181)
  9. c语言删除链表中特定元素,Leetcode203. 删除链表中的元素_C语言
  10. html csv 中文乱码,csv 中文乱码
  11. 使用计算机对炼钢过程进行实时监控,转炉炉气分析与“投弹”检测相结合在自动化炼钢技术中的应用...
  12. java 利用时间生成主键
  13. http://jingyan.baidu.com/article/636f38bb3eb78ad6b8461082.html
  14. leaks will report false positives while the environment variable NSZombiesEnable is active
  15. vb.net 教程 11-1 打印组件 1 基础
  16. Excel 提取单元格中的数字、中/英文方法
  17. Linux内核4.14版本:ARM64的内核启动过程(一)——start_kernel之前
  18. 墨卡托坐标转GPS坐标
  19. 吉林大学单片机实验课实验五——重量测量
  20. 打破985校史!她以独作身份投中顶刊,曾因换方向重读博士7年,科研之路也“坎坎坷坷”……...

热门文章

  1. C++中override overload overwrite
  2. iOS CMPedometer 获取计步数据异常解决办法
  3. 6-6 调查 :在6.3.1节编写的程序favorite_languages.py中执行以下操作
  4. solodity实现erc721 宠物
  5. 六月A股还有没有好戏 十大博客看后市
  6. 总线式-七氟丙烷灭火系统结构图
  7. [2016/7/11]白山云科技实习第一天
  8. internet信息服务“出现错误,并非所有功能被成功更改” 或者win7 IIS7 安装失败 报状态为: 0x80070bc9错误 的 **终极解决办法!
  9. android 卡片旋转动画,Android-显示卡片翻转的动画片效果
  10. C6000汇编语言实现乘法,C6000(四)-汇编.ppt