2017-05-18 19:25:43 jiji_vip 阅读数 19504

MATLAB实现静态图像分割

待处理图像是一张药板图,我们的处理目标有以下几个:
1. 将药板从黑色背景中分离(药板部分显示为白色,背景显示为黑色);
2. 根据分割结果将药板旋转至水平;
3. 提取药板中的药丸的信息;
待处理照片


  • 首先将药板从黑色背景中分离出来,用otsu对图像进行分割,很简单,代码是王道。
clc;clear all;  
H=imread('C:\Users\Administrator\Desktop\1\1.tiff');       
I=rgb2gray(H);  
T=graythresh(I);    %采用Otsu方法计算最优阈值T对图像二值化;  
Ibw1 = im2bw(I,T);
figure, imshow(Ibw1);title('Otsu-图1');

只贴一个 结果:
这是图
接着将孔洞填充:

clear,clc,close all;
I=imread('C:\Users\Administrator\Desktop\1\1.tiff');
bw=rgb2gray(I);
bw=im2bw(I,graythresh(bw));%采用Otsu方法
BW1 = imfill(bw, 'holes');%孔洞填充
figure;imshow(BW1);title('分离出的药板')

是不是很纯洁了

  • 将药板旋转至水平
    将药板二值化之后,取出边缘,Hough变换求出线段斜率,得到角度,然后通过imrotate()函数进行自动旋转。这一步重点在于标出直线,求得斜率。
    霍夫变换传送门

废话不多说,代码:

clear,clc,close all;
I=imread('C:\Users\Administrator\Desktop\1\1.tiff');
bw=rgb2gray(I);
bw=im2bw(I,graythresh(bw));%采用Otsu方法
bw=double(bw);
BW=edge(bw,'canny');
%霍夫变换
[H,T,R]=hough(BW);
P=houghpeaks(H,4,'threshold',ceil(0.3*max(H(:))));
lines=houghlines(BW,T,R,P,'FillGap',50,'MinLength',7);
max_len = 0;
%figure,imshow(BW),title('直线标识产物');
%hold on;
for k=1:length(lines)
xy=[lines(k).point1;lines(k).point2];
%plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% 标出线段的起始和终端点
%plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
%plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
    len=norm(lines(k).point1-lines(k).point2);
    Len(k)=len;
    if (len>max_len)
        max_len=len;
        xy_long=xy;
    end
end
[L1 Index1]=max(Len(:));
% 求得最长线段的斜率
K1=-(lines(Index1).point1(2)-lines(Index1).point2(2))/...
    (lines(Index1).point1(1)-lines(Index1).point2(1))
angle=atan(K1)*180/pi
A = imrotate(I,-angle,'bilinear','crop');% imrorate 是逆时针的所以取负
figure; imshow(A);title('旋转后的药板')

现在老规矩就是贴上结果:
这是提取的边缘
旋转正的图片
旋转的角度8.9726
当然你可以用眼睛看着调,除了有点low之外。。

  • 提取药板中药丸的位置信息
    简单点说就是把药丸框起来。用到regionprops函数。
%在二值图中确定出标记位置信息
B=rgb2gray(A);
B=im2bw(A,graythresh(A));
L = bwlabel(~B);
stats = regionprops(L, 'BoundingBox');
%在旋转后的图像中标记
figure; imshow(A);title('旋转后的药板(标记药丸位置)')
hold on;
for i = 1 : length(stats)
    if stats(i).BoundingBox(1)>10
    rectangle('Position', stats(i).BoundingBox, 'edgecolor', 'r','LineWidth',3);
    end
end

运行结果:
标记药丸
可能有人说了,你咋标成这个样子??这我也不想啊,otsu分割完只能弄成这样。

  • 基于颜色特征的区域分割
    “早干嘛去了,一开始就应该用这个东西。。”我不服啊,什么东西刚开始弄就很十全十美。代码有个重构的过程,人类更有个从猿人进化到智人的阶段。
    首先看张图:
    这是图
    你有什么发现?是不是感觉两个图就像一个夫妻,一阴一阳,一上一下。没错,这是原始图片分别在y颜色空间和cb颜色空间图像。
ycbcr=rgb2ycbcr(A);
y=ycbcr(:,:,1);
cb=ycbcr(:,:,2);
cr=ycbcr(:,:,3);

thr_y=graythresh(y);
bw_y=im2bw(y,thr_y);

thr_cb=graythresh(cb);
bw_cb=im2bw(cb, thr_cb);

将两个颜色空间的图像取反,相加,即B=~bw_y+~bw_cb,结果如下:
这图有没有很强
剩下的我想你们也知道该怎么办——做一下形态学运算,再框起来
结果:
这是最后的图
附代码,亲测

clear,clc,close all;
I=imread('C:\Users\Administrator\Desktop\1\1.tiff');
bw=rgb2gray(I);
bw=im2bw(I,graythresh(bw));%采用Otsu
%将药板从黑色背景中分离
BW1 = imfill(bw, 'holes');
figure;imshow(BW1);title('分离出的药板')

bw=double(bw);
BW=edge(bw,'canny');
%哈佛变换
[H,T,R]=hough(BW);%H是霍夫变换矩阵,T、R是p和θ值向量,在这些值上产生霍夫变换BW是二值图像
P=houghpeaks(H,4,'threshold',ceil(0.3*max(H(:))));
lines=houghlines(BW,T,R,P,'FillGap',50,'MinLength',7);%%lines为结构数组,长度等于找到的线段数
max_len = 0;
for k=1:length(lines)
    xy=[lines(k).point1;lines(k).point2];
    len=norm(lines(k).point1-lines(k).point2);
    Len(k)=len;
    if (len>max_len)
        max_len=len;
        xy_long=xy;
    end
end
[L1 Index1]=max(Len(:));
% 求得线段的斜率
K1=-(lines(Index1).point1(2)-lines(Index1).point2(2))/...
    (lines(Index1).point1(1)-lines(Index1).point2(1))
angle=atan(K1)*180/pi
A = imrotate(I,-angle,'bilinear','crop');% imrate 是逆时针的所以取负

%颜色特征的区域分割
ycbcr=rgb2ycbcr(A);
y=ycbcr(:,:,1);
cb=ycbcr(:,:,2);
cr=ycbcr(:,:,3);

thr_y=graythresh(y);
bw_y=im2bw(y,thr_y);

thr_cb=graythresh(cb);
bw_cb=im2bw(cb, thr_cb);

B=~(~bw_y+~bw_cb);

se=strel('disk',5);
B=imclose(B,se);
B=imopen(B,se);

%确定出标记位置
L = bwlabel(~B);
stats = regionprops(L, 'BoundingBox');
%在旋转后的图像中标记

figure; imshow(A);title('旋转后的药板1(标记药丸位置)')
hold on;
for i = 1 : length(stats)
    if stats(i).BoundingBox(1)>10
    rectangle('Position', stats(i).BoundingBox, 'edgecolor', 'r','LineWidth',3);
    end
end
2018-07-04 11:00:55 qq_38096703 阅读数 10692
待处理图像是一张药板图,我们的处理目标有以下几个: 
1. 将药板从黑色背景中分离(药板部分显示为白色,背景显示为黑色); 
2. 根据分割结果将药板旋转至水平; 

3. 提取药板中的药丸的信息; 

采用两种方法执行,详细注释见代码

clc;clear all;  
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%% 法一:用otsu对图像进行分割
img=imread('1.jpg');       
I=rgb2gray(img);  
T=graythresh(I);    %采用Otsu方法计算最优阈值T对图像二值化;  
Ibw1 = im2bw(I,T);
figure, imshow(Ibw1);title('Otsu-图1');
%% 接着将孔洞填充
BW1 = imfill(Ibw1, 'holes');%孔洞填充
figure;imshow(BW1);title('分离出的药板')
%% 将药板旋转至水平 
%将药板二值化之后,取出边缘,Hough变换求出线段斜率,得到角度,然后通过imrotate()函数进行自动旋转。这一步重点在于标出直线,求得斜率。
bw=double(Ibw1);
BW=edge(bw,'canny');
%霍夫变换
[H,T,R]=hough(BW); %H:累计数组  ,T:H对应的θ, R:H对应的ρ,实际上H的大小就是R×T,
P=houghpeaks(H,4,'threshold',ceil(0.3*max(H(:))));%峰值提取 --peaks = houghpeaks(H,numpeaks,param1, val1)  
%Numpeaks:指定需要检测的峰值个数; Param1:可以是'Threshold'或'NHoodSize'
%'Threshold'-指定峰值的域值,默认是0.5*max(H(:)); 
%'NHoodSize'-是个二维向量[m,n],检测到一个峰值后,将峰值周围[m,n]内元素置零。
lines=houghlines(BW,T,R,P,'FillGap',50,'MinLength',7);%画直线段 lines = houghlines(BW,theta, rho, peaks,param1, val1)
%Lines:结构数组,大小等于检测到的直线段数,每个单元包含point1、point2:线段的端点,Theta、rho:线段的theta和rho
max_len = 0;
figure,imshow(BW),title('直线标识产物');
hold on;
for k=1:length(lines)
xy=[lines(k).point1;lines(k).point2];
%plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% 标出线段的起始和终端点
%plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
%plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
    len=norm(lines(k).point1-lines(k).point2);
    Len(k)=len;
    if (len>max_len)
        max_len=len;
        xy_long=xy;
    end
end
[L1 Index1]=max(Len(:));
% 求得最长线段的斜率
K1=-(lines(Index1).point1(2)-lines(Index1).point2(2))/(lines(Index1).point1(1)-lines(Index1).point2(1));
angle=atan(K1)*180/pi;
A = imrotate(img,-angle,'bilinear','crop');% imrorate 是逆时针的所以取负
figure; imshow(A);title('旋转后的药板')
%% 提取药板中药丸的位置信息 --简单点说就是把药丸框起来。用到regionprops函数。
%在二值图中确定出标记位置信息
B=rgb2gray(A);
B=A;
B=im2bw(A,graythresh(A));
L = bwlabel(~B);%返回一个和B大小相同的L矩阵,包含了标记了B中每个连通区域的类别标签,这些标签的值为1、2、num(连通区域的个数)。
                %n的值为4或8,表示是按4连通寻找区域,还是8连通寻找,默认为8。
stats = regionprops(L, 'BoundingBox');%用来度量图像区域属性的函数。
    %测量标注矩阵L中每一个标注区域的一系列属性。L中不同的正整数元素对应不同的区域。
    %例如:L中等于整数1的元素对应区域1;L中等于整数2的元素对应区域2;以此类推。
    %返回值STATS是一个长度为max(L(:))的结构数组,结构数组的相应域定义了每一个区域相应属性下的度量。
    %properties 可以是由逗号分割的字符串列表、饱含字符串的单元数组、单个字符串 'all' 或者 'basic'。
    %如果 properties 等于字符串 'all',则所有下述字串列表中的度量数据都将被计算。
    %如果 properties 没有指定或者等于 'basic',则属性: 'Area', 'Centroid', 和 'BoundingBox' 将被计算。

%在旋转后的图像中标记
figure; imshow(A);title('旋转后的药板(标记药丸位置)')
hold on;
for i = 1 : length(stats)
    if stats(i).BoundingBox(1)>10
    rectangle('Position', stats(i).BoundingBox, 'edgecolor', 'r','LineWidth',3);
    end
end
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 法二:基于颜色特征的区域分割 
ycbcr=rgb2ycbcr(A);
y=ycbcr(:,:,1); %亮度
cb=ycbcr(:,:,2); %彩度
cr=ycbcr(:,:,3); %浓度

thr_y=graythresh(y);
bw_y=im2bw(y,thr_y);
figure; 
imshow(bw_y);

thr_cb=graythresh(cb);
bw_cb=im2bw(cb, thr_cb);
figure; 
imshow(bw_cb);
%将两个颜色空间的图像取反,相加
B1=~(~bw_y+~bw_cb);
%做一下形态学运算,再框起来
se=strel('disk',5); %%生成圆形结构元素
B1=imclose(B1,se); %%用生成的结构元素对图像进行闭运算
B1=imopen(B1,se); %%用生成的结构元素对图像进行开运算

%确定出标记位置
L1 = bwlabel(~B1);
stats1 = regionprops(L1, 'BoundingBox');
%在旋转后的图像中标记

figure; imshow(A);title('旋转后的药板1(标记药丸位置)')
hold on;
for i = 1 : length(stats1)
    if stats1(i).BoundingBox(1)>10
    rectangle('Position', stats1(i).BoundingBox, 'edgecolor', 'r','LineWidth',3);
    end
end
参考:https://blog.csdn.net/jiji_vip/article/details/72487804?utm_source=itdadao&utm_medium=referral
2019-05-25 21:18:48 baidu_26954625 阅读数 112

你有四个装药丸的罐子,每个药丸都有一定的重量,被污染的药丸是没被污染的重量+1.只称量一次,如何判断哪个罐子的药被污染了?
在这里插入图片描述

2019-11-06 20:18:20 qq_41946557 阅读数 41

有20瓶药丸,其中19瓶药丸质量相同为1克,剩下一瓶药丸质量为1.1克。瓶子中有
无数个药丸。要求用一次天平找出药丸质量1.1克的药瓶。
 

解答:

可以从药丸的数量上来制造差异:从第i瓶药丸中取出i个药丸,然后一起称重。 可以知道,
如果第i瓶药丸重1.1克/粒,那么称重结果就会比正常情况下重0.1 *i克

 

 

 

是不是不懂:

 

 

 

别急:

解法:有时候,严格的限制条件有可能反倒是解题的线索。在这个问题中,限制条件是天平只能用一次。因为天平只能用一次,我们也得以知道一个有趣的事实:一次必须同时称很多药丸,其实更准确地说,是必须从19瓶拿出药丸进行称重。否则,如果跳过两瓶或更多瓶药丸,又该如何区分没称过的那几瓶呢?别忘了,天平只能用一次。

那么,该怎么称重取自多个药瓶的药丸,并确定哪一瓶装有比较重的药丸?假设只有两瓶药丸,其中一瓶的药丸比较重。每瓶取出一粒药丸,称得重量为2.1克,但无从知道这多出来的0.1克来自哪一瓶。我们必须设法区分这些药瓶。

如果从药瓶#1取出一粒药丸,从药瓶#2取出两粒药丸,那么,称得重量为多少呢?结果要看情况而定。如果药瓶#1的药丸较重,则称得重量为3.1克。如果药瓶#2的药丸较重,则称得重量为3.2克。这就是这个问题的解题窍门。

称一堆药丸时,我们会有个“预期”重量。而借由预期重量和实测重量之间的差别,就能得出哪一瓶药丸比较重,前提是从每个药瓶取出不同数量的药丸。

将之前两瓶药丸的解法加以推广,就能得到完整解法:从药瓶#1取出一粒药丸,从药瓶#2取出两粒,从药瓶#3取出三粒,依此类推。如果每粒药丸均重1克,则称得总重量为210克(1 + 2 + … + 20 = 20 * 21 / 2 = 210),“多出来的”重量必定来自每粒多0.1克的药丸。药瓶的编号可由算式(weight – 210 grams) / 0.1 grams得出。因此,若这堆药丸称得重量为211.3克,则药瓶#13装有较重的药丸。

2019-08-20 16:55:36 qq_43606352 阅读数 18

问题描述:你有四个装药丸的罐子,每个药丸都有一定的重量,被污染的药丸是没污染药丸的重量+1,只称量一次,如何判断哪个罐子的药被污染了?

解答:四个罐子编号为1,2,3,4,在 1 号中取出 1 个药丸,2 号取出 2 个,3 号取出 4 个,4 号取出 8 个药丸,4 个罐子共取出 15 个药丸,称重后减去 15 个没被污染药丸的重量,则:

0 :没有药丸污染

1 :1 号罐子被污染

2 :2 号罐子被污染

3 :1,2 号罐子被污染

4 :3 号罐子被污染

5 :1,3 号罐子被污染

6 :2,3 号罐子被污染

7 :1,2,3 号罐子被污染

8 :4 号罐子被污染

9 :1,4 号罐子被污染

10 :2,4 号罐子被污染

11 :1,2,4 号罐子被污染

12 :3,4 号罐子被污染

13 :1,3,4 号罐子被污染

14 :2,3,4 号罐子被污染

15 :4 个罐子全部被污染

被污染的药丸

阅读数 222

天平秤药丸

阅读数 403

博文 来自: wangfengfan1
没有更多推荐了,返回首页