Как рассчитать площадь под кривой на изображении с помощью MATLAB? - PullRequest
5 голосов
/ 04 июня 2010

альтернативный текст http://internationalpropertiesregistry.com/Server/showFile.php?file=%2FUpload%2Fstatistics.gifc49ca28823a561a41d09ef9adbb5e0c5.gif

Единицей оси x является часы (h), всего 24 часа.

Единицей оси Y являются миллионы (m).

Как рассчитать площадь под красной кривой на изображении в единицах m*h?

Важное обновление

Доступно только изображение (не данные), и я хочу вычислить площадь программно .

Ответы [ 4 ]

6 голосов
/ 04 июня 2010

Вот интересное решение :). Кстати, он использует 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

3 голосов
/ 07 июня 2010

Сложность создания полностью автоматизированного решения заключается в том, что вам потребуется жестко закодировать в своем решении определенные предположения о входных изображениях, которые вы собираетесь обрабатывать. Если эти предположения не соответствуют всем потенциальным изображениям, с которыми вы можете столкнуться, полностью автоматизированное решение не даст достоверных результатов, и попытка расширить полностью автоматизированное решение для обработки всех возможные входные данные, вероятно, приведут к тому, что он превратится в непонятный и сложный беспорядок кода.

Если вы сомневаетесь в вариативности функций ваших входных изображений, лучше всего подойдет решение, например Джейкоба с некоторым взаимодействием с пользователем. Если вы можете быть уверенными в том, что функции ваших входных изображений следуют строгому набору правил, тогда можно рассмотреть автоматизированное решение.

В качестве примера ниже приведен некоторый автоматизированный код, который я написал, чтобы приблизить область под красной кривой на вашем графике. Поскольку я использовал приведенный выше график в качестве руководства, для его работы необходимо выполнить ряд условий:

  • Красные пиксели нанесенной линии должны быть однозначно описаны на изображении как содержащие зеленые и синие цветовые компоненты, равные 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. Бинарное изображение greenLine суммируется по каждому столбцу с помощью функции SUM , давая вектор 1-by-c, где каждый элемент представляет собой количество пикселей линии сетки в каждом столбце изображения. .
  2. Элементы этого вектора, которые больше r/2 (половина числа строк в изображении) указывают столбцы изображения, которые содержат вертикальную линию сетки. Индексы этих столбцов находятся с помощью функции НАЙТИ .
  3. Попарные разности между этими индексами столбцов находятся с помощью функции DIFF . Это дает вектор, содержащий ширину (в пикселях) пробелов между линиями сетки.
  4. Наконец, функция MEAN используется для вычисления средней ширины промежутков между всеми линиями сетки на изображении.

При вычислении h единственное отличие состоит в том, что сумма выполняется по каждой строке и r/2 заменяется на c/2 (половина числа столбцов в изображении).

1 голос
/ 04 июня 2010

Так как у вас есть только доступное изображение, я предлагаю вам интегрировать на глаз: подсчитайте количество целых квадратов под красной линией.

Для каждого квадрата, который пересекает красная линия, решите, включать ли его в счет или нет, в зависимости от того, сколько находится ниже линии. Не пытайтесь оценить, какая часть квадрата лежит ниже красной линии, в лучшем случае это даст вам иллюзию большей точности.

РЕДАКТИРОВАТЬ: Я посчитал зеленые квадраты для вас, ответ 168 м.ч

0 голосов
/ 04 июня 2010

Поскольку это не похоже на «функцию», которую вы могли бы интегрировать, я бы использовал метод численного интегрирования. Я всегда неравнодушен к trapz, который использует " трапециевидное правило " для численного интегрирования.

Что-то вроде:

area = trapz(data);

должно быть достаточно.

Надеюсь, это поможет,

Будет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...