Как я вычисляю область под кривой в изображении с MATLAB?

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

Единица оси X является часами (h), и всего существует 24 часа.

Единица оси y является миллионами (m).

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

Важное ОБНОВЛЕНИЕ

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

5
задан gnovice 15 June 2010 в 15:39
поделиться

4 ответа

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

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

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

  • Красные пиксели нанесенной линии должны быть однозначно описаны на изображении как содержащие компоненты зеленого и синего цвета, равные равным 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


ОБЪЯСНЕНИЕ:

I ' Я подробно расскажу о шагах, необходимых для вычисления w :

  1. Двоичное изображение greenLine суммируется по каждому столбцу с помощью функции СУММ , что дает 1-на-c вектор, где каждый элемент является подсчетом количества пикселей линии сетки в каждом столбце изображения.
  2. Элементы этого вектора, которые больше, чем r / 2 (половина числа строк в изображении), указывают столбцы изображения, которые содержат вертикальную линию сетки. Индексы этих столбцов находятся с помощью функции НАЙТИ .
  3. Попарные различия между этими индексами столбцов находятся с помощью функции DIFF . Это дает вектор, содержащий ширину (в пикселях) промежутков между линиями сетки.
  4. Наконец, функция MEAN используется для вычисления средней ширины промежутков между всеми линиями сетки на изображении.

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

3
ответ дан 13 December 2019 в 22:02
поделиться

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

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

EDIT: Я посчитал зелёные квадраты для вас, ответ 168 м.ч

1
ответ дан 13 December 2019 в 22:02
поделиться

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

6
ответ дан 13 December 2019 в 22:02
поделиться

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

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

area = trapz(data);

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

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

Уилл

0
ответ дан 13 December 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: