如何使用MATLAB计算图像中曲线下的面积?

时间:2010-06-04 12:17:44

标签: matlab image-processing

alt text http://internationalpropertiesregistry.com/Server/showFile.php?file=%2FUpload%2Fstatistics.gifc49ca28823a561a41d09ef9adbb5e0c5.gif

x轴的单位是小时(h),总共有24小时。

y轴的单位是数百万(m)。

如何以m*h

为单位计算图像中红色曲线下的面积

重要更新

只有图像可供使用(不是数据),我想以编程方式计算区域。

4 个答案:

答案 0 :(得分:6)

这是一个有趣的解决方案:)。顺便说一句,它使用bwfill(类似于imfill),需要一些用户互动。

代码

%# Constants
gray_value_curve = 2;
gray_value_box = 3;
area_box_in_units = 10;

%# Read the image
I = imread('C:\p23\graph.gif');
%# Find the area of a unit block
figure(1);
imshow(I,[]);
[BS sq_elem] = bwfill;   
imshow(BS,[]);
%# Get the dimensions to make the estimate more accurate
X = zeros(size(BS));
X(sq_elem) = 1;
s = regionprops(X,'Area','BoundingBox');
block_area = s.Area + 2*(s.BoundingBox(3)-1) + 2*(s.BoundingBox(4)-1) + 4;

%#Find the area under the curve
I( ~(I == gray_value_curve | I == gray_value_box) ) = 0;
figure(2);
imshow(I,[]);
[BA area_curve_elem] = bwfill;
imshow(BA,[]);
%# Area under the curve
curve_area = numel(area_curve_elem);

%# Display the area in the required units
area = area_box_in_units*curve_area/block_area;
disp(area);

输出

113.5259

图1 alt text 图2 alt text

答案 1 :(得分:3)

创建全自动解决方案的难点在于,它需要您将有关您要处理的输入图像的某些假设硬编码到解决方案中。如果这些假设不适用于所有您可能遇到的潜在图像,那么全自动解决方案将无法提供值得信赖的结果,并尝试扩展全自动解决方案以处理所有可能的输入都可能导致它膨胀成难以理解和复杂的代码。

如果对输入图像功能的可变性存在疑问,那么Jacob's某些用户交互的解决方案通常是最佳选择。如果您某些输入图像的功能遵循严格的规则,则可以考虑使用自动解决方案。

例如,下面是我编写的一些自动代码,用于近似图表中红色曲线下的区域。由于我使用上面的图表作为指南,因此必须满足一些条件才能工作:

  • 绘制线条的红色像素必须在图像中唯一描述为包含等于0的绿色和蓝色分量以及等于1的红色分量。
  • 网格线的绿色像素必须在图像中唯一描述为包含小于1的红色和蓝色分量以及等于1的绿色分量。
  • 轴线的蓝色像素必须在图像中唯一描述为包含等于0的红色和绿色成分以及等于1的蓝色成分。
  • 网格线和轴线必须始终在水平或垂直方向上精确对齐。
  • 网格线的长度必须超过图像宽度和高度的一半。
  • x轴必须是图像中最长的水平蓝线。
  • 网格线的长度必须始终为1个像素。

根据输入图像的上述条件,以下代码可用于近似红色曲线下的区域而无需用户输入:

[img,map] = imread('original_chart.gif');  %# Read the indexed image
[r,c] = size(img);                         %# Get the image size

redIndex = find((map(:,1) == 1) & ...    %# Find the red index value
                (map(:,2) == 0) & ...
                (map(:,3) == 0))-1;
greenIndex = find((map(:,1) < 1) & ...   %# Find the green index value
                  (map(:,2) == 1) & ...
                  (map(:,3) < 1))-1;
blueIndex = find((map(:,1) == 0) & ...   %# Find the blue index value
                 (map(:,2) == 0) & ...
                 (map(:,3) == 1))-1;

redLine = (img == redIndex);      %# A binary image to locate the red line
greenLine = (img == greenIndex);  %# A binary image to locate the grid lines
blueLine = (img == blueIndex);    %# A binary image to locate the axes lines

w = mean(diff(find(sum(greenLine,1) > r/2)));  %# Compute unit square width
h = mean(diff(find(sum(greenLine,2) > c/2)));  %# Compute unit square height
squareArea = w*h;                              %# Compute unit square area

[maxValue,maxIndex] = max(redLine);          %# Find top edge of red line
x = find(maxValue > 0);                      %# Find x coordinates of red line
y = maxIndex(maxValue > 0);                  %# Find y coordinates of red line
[maxValue,maxIndex] = max(sum(blueLine,2));  %# Find row index of x axis
y = maxIndex-y;                              %# Zero the y coordinate
totalArea = trapz(x,y)/squareArea;           %# Compute the area under the curve

其中给出了以下结果:

squareArea = 460.6 square pixels
totalArea = 169.35 m*h


说明

我将详细介绍计算w

所涉及的步骤
  1. 使用函数SUM将二进制图像greenLine沿每列求和,得到1-by-c向量,其中每个元素是每列中网格线像素数的计数图像。
  2. 此向量的元素大于r/2(图像中行数的一半)表示包含垂直网格线的图像列。可以使用函数FIND找到这些列的索引。
  3. 使用函数DIFF找到这些列索引之间的成对差异。这给出了一个向量,包含网格线之间空格的宽度(以像素为单位)。
  4. 最后,函数MEAN用于计算图像中所有网格线之间的空间平均宽度。
  5. 计算h时,唯一的区别是总和是按每行执行的,而r/2则替换为c/2(图像中列数的一半)。

答案 2 :(得分:1)

由于你只有图像可用,我建议你用眼睛整合:计算红线下面的整个正方形的数量。

对于红线相交的每个方格,根据线下方的数量决定是否将其包含在计数中。不要试图估计红线下方有多少正方形,最多会给你一种更准确的幻觉。

编辑:我为你计算了绿色方块,答案是168 m.h

答案 3 :(得分:0)

由于这似乎不是你可以整合的“功能”,我会使用数值积分技术。我总是偏向于使用“trapezoidal rule”进行数值积分的trapz

类似的东西:

area = trapz(data);

应该足够了。

希望有所帮助,

威尔