从电泳凝胶图像测量加权平均长度

时间:2011-11-22 20:25:42

标签: matlab image-processing

背景

我的问题涉及从电泳凝胶中提取特征(见下文)。在该凝胶中,从顶部装载DNA并使其在电压梯度下迁移。凝胶具有筛子,因此较小的分子比较长的分子迁移得更远,导致DNA长度分离。分子越高,它就越长。

问题:

在该图像中,有9个泳道,每个泳道都有独立的DNA来源。我有兴趣测量每条车道的平均位置(y轴上的值)。 我对图像处理很陌生,但我知道MATLAB,我可以用R来解决这个问题。如果有人能告诉我如何找到每条车道的平均值,我真的很感激。

gel_image

4 个答案:

答案 0 :(得分:5)

这是我的尝试。它要求凝胶很好(即直通道和凝胶不应旋转),但应该相当普遍地工作。请注意,需要调整两个与图像大小相关的参数,以使其适用于不同大小的图像。

%# first size-dependent parameter: should be about 1/4th-1/5th
%# of the lane width in pixels.
minFilterWidth = 10;

%# second size-dependent parameter for filtering the 
%# lane profiles
gaussWidth = 5;

%# read the image, normalize to 0...1
img = imread('http://img823.imageshack.us/img823/588/gele.png');
img = rgb2gray(img);
img = double(img)/255;

%# Otsu thresholding to (roughly) find lanes
thMsk = img < graythresh(img);

enter image description here

%# count the mask-pixels in each columns. Due to 
%# lane separation, there will be fewer pixels
%# between lanes
cts = sum(thMsk,1);

enter image description here

%# widen the local minima, so that we get a nice
%# separation between lanes
ctsEroded = imerode(cts,ones(1,minFilterWidth));

%# use imregionalmin to identify the separation 
%# between lanes. Invert to get a positive mask
laneMsk = ~repmat(imregionalmin(ctsEroded),size(img,1),1);

带有将用于分析的车道的图像

enter image description here

%# for each lane, create an averaged profile
lblMsk = bwlabel(laneMsk);
nLanes = max(lblMsk(:));

profiles = zeros(size(img,1),nLanes);
midLane = zeros(1,nLanes);

for i = 1:nLanes
profiles(:,i) = mean(img.*(lblMsk==i),2);
midLane(:,i) = mean(find(lblMsk(1,:)==i));
end

%# Gauss-filter the profiles (each column is an
%# averaged intensity profile
G = exp(-(-gaussWidth*5:gaussWidth*5).^2/(2*gaussWidth^2));
G=G./sum(G);
profiles = imfilter(profiles,G','replicate'); %'

enter image description here

%# find the minima
[~,idx] = min(profiles,[],1);

%# plot
figure,imshow(img,[])
hold on, plot(midLane,idx,'.r')

enter image description here

答案 1 :(得分:4)

这是我用一个简单的模板来实现这一目的的交互方式:

% Load image
img = imread('gel.png');
img = rgb2gray(img);

% Identify lanes
imshow(img)
[x,y] = ginput;

% Invert image
img = max(img(:)) - img;

% Subtract background
[xn,yn] = ginput(1);
noise   = img((yn-2):(yn+2), (xn-2):(xn+2));
noise   = mean(noise(:));
img     = img - noise;

% Calculate means
means = (1:size(img,1)) * double(img(:,round(x))) ./ sum(double(img(:,round(x))), 1);

% Plot
hold on
plot(x, means, 'r.')

enter image description here

答案 2 :(得分:4)

要做的第一件事是将RGB图像转换为灰度:

gr = rgb2gray(imread('gelk.png'));

然后,使用imhist查看图像强度直方图。注意到有什么好玩的吗?使用imcontrast(imshow(gr))拉出对比度调整工具。我发现在主要强度峰值之后消除奇怪的东西是有益的。

图像处理任务本身可以分为几个步骤。

  1. 分开每条车道
  2. 识别('段')每个车道中的乐队
  3. 计算乐队的位置
  4. 步骤1 可以“手动”完成,如果保证了车道宽度。如果没有,Hough transform提供的线路检测可能就是这样。图像处理工具箱上的文档有一个关于这个主题的非常好的教程。我的代码概括了该教程,为您的图像提供了更好的参数。我只用了几分钟,我相信你可以通过进一步调整参数来改善结果。

    第2步可以通过几种方式完成。最简单的技术是Otsu用于阈值灰度图像的方法。此方法通过确定最小化 intra 类方差的阈值来工作,或者等效地,最大化 inter - 类方差。 Otsu的方法在MATLAB中作为graythresh函数出现。如果Otsu的方法效果不佳,您可以尝试multi-level Otsu或其他一些histogram based threshold determination methods

    通过计算分段带像素的平均y值,可以按照建议完成

    步骤3 。这就是我的代码所做的,虽然我已将检查限制在每个通道的中心列,以防分离关闭。我担心结果可能不如计算波段质心和使用它的位置那么好。


    这是我的解决方案:

    function [locations, lanesBW, lanes, cols] = segmentGel(gr)
    
    %%# Detect lane boundaries
    unsharp = fspecial('unsharp'); %# Sharpening filter
    I = imfilter(gr,unsharp); %# Apply filter
    bw = edge(I,'canny',[0.01 0.3],0.5); %# Canny edges with parameters
    [H,T,R] = hough(bw); %# Hough transform of edges
    P = houghpeaks(H,20,'threshold',ceil(0.5*max(H(:)))); %# Find peaks of Hough transform
    lines = houghlines(bw,T,R,P,'FillGap',30,'MinLength',20); %# Use peaks to identify lines
    
    %%# Plot detected lines above image, for quality control
    max_len = 0;
    imshow(I);
    hold on;
    for k = 1:length(lines)
       xy = [lines(k).point1; lines(k).point2];
       plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
    
       %# Plot beginnings and ends of lines
       plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
       plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
    
       %# Determine the endpoints of the longest line segment
       len = norm(lines(k).point1 - lines(k).point2);
       if ( len > max_len)
          max_len = len;
       end
    end
    hold off;
    
    %%# Use first endpoint of each line to separate lanes
    cols = zeros(length(lines),1);
    for k = 1:length(lines)
        cols(k) = lines(k).point1(1);
    end
    cols = sort(cols); %# The lines are in no particular order
    
    lanes = cell(length(cols)-1,1);
    for k = 2:length(cols)
        lanes{k-1} = im2double( gr(:,cols(k-1):cols(k)) ); %# im2double for compatibility with greythresh
    end
    otsu = cellfun(@graythresh,lanes); %# Calculate threshold for each lane
    lanesBW = cell(size(lanes));
    for k = 1:length(lanes)
        lanesBW{k} = lanes{k} < otsu(k); %# Apply thresholds
    end    
    
    %%# Use segmented bands to determine migration distance
    locations = zeros(size(lanesBW));
    for k = 1:length(lanesBW)
        width = size(lanesBW{k},2);    
        [y,~] = find(lanesBW{k}(:,round(width/2))); %# Only use center of lane
        locations(k) = mean(y);
    end
    

    我建议您在将其用于实际研究目的之前,不仅要仔细检查每个输出值,还要检查功能的每个步骤的结果。为了获得非常好的结果,您将不得不阅读有关Hough变换,Canny边缘检测和Otsu方法的一些信息,然后调整参数。您可能还必须改变车道的分裂方式;此代码假定在图像的任一侧检测到线条。

答案 3 :(得分:3)

让我添加另一个与@JohnColby的概念类似的实现,只是没有手动用户交互:

%# read image
I = rgb2gray(imread('gele.png'));

%# middle position of each lane
%# (assuming lanes are somewhat evenly spread and of similar width)
x = linspace(1,size(I,2),10);
x = round( (x(1:end-1)+x(2:end))./2 );

%# compute the mean value across those columns
m = mean(I(:,x));

%# find the y-indices of the mean values
[~,idx] = min( bsxfun(@minus, double(I(:,x)), m) );

%# show the result
figure(1)
imshow(I, 'InitialMagnification',100, 'Border','tight')
hold on, plot(x, idx, ...
    'Color','r', 'LineStyle','none', 'Marker','.', 'MarkerSize',10)

screenshot

并应用于较小的图片:

screenshot2