Единица оси X является часами (h
), и всего существует 24 часа.
Единица оси y является миллионами (m
).
Как я вычисляю область под красной кривой в изображении в единицах m*h
?
Важное ОБНОВЛЕНИЕ
Только изображение легко доступно (не данные), и я хочу вычислить область программно.
Сложность создания полностью автоматизированного решения заключается в том, что вам потребуется жестко запрограммировать в свое решение определенные предположения о входных изображениях, которые вы собираетесь обрабатывать. Если эти предположения не верны для всех потенциальных изображений, с которыми вы можете столкнуться, полностью автоматизированное решение не даст достоверных результатов, и попытка расширить полностью автоматизированное решение для обработки всех возможные входы, скорее всего, приведут к тому, что он превратится в непонятный и сложный беспорядок кода.
Если вы сомневаетесь в вариативности характеристик входных изображений, лучше всего подойдет решение типа Джейкоба с некоторым взаимодействием с пользователем. Если вы уверены в том, что особенности ваших входных изображений соответствуют строгому набору правил, тогда можно рассмотреть автоматизированное решение.
В качестве примера ниже приведен автоматизированный код, который я написал для аппроксимации площади под красной кривой на вашем графике. Поскольку я использовал приведенный выше график в качестве руководства, существует ряд условий, которые должны быть выполнены для его работы:
В соответствии с вышеуказанными условиями для входного изображения следующий код может использоваться для аппроксимации площади под красной кривой без ввода данных пользователем:
[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
:
greenLine
суммируется по каждому столбцу с помощью функции СУММ , что дает 1-на-c
вектор, где каждый элемент является подсчетом количества пикселей линии сетки в каждом столбце изображения. r / 2
(половина числа строк в изображении), указывают столбцы изображения, которые содержат вертикальную линию сетки. Индексы этих столбцов находятся с помощью функции НАЙТИ . При вычислении h
единственное отличие состоит в том, что сумма выполняется по каждой строке, а r / 2
заменяется на c / 2
(половина количество столбцов на изображении).
Поскольку у вас есть только изображение, я предлагаю вам интегрировать на глаз: подсчитайте количество целых квадратов под красной линией.
Для каждого квадрата, который пересекает красная линия, решите, включать или не включать его в подсчет в зависимости от того, сколько лежит ниже линии. Не пытайтесь оценить, какая часть квадрата лежит под красной линией, в лучшем случае это даст вам иллюзию большей точности.
EDIT: Я посчитал зелёные квадраты для вас, ответ 168 м.ч
Вот интересное решение :). Кстати, он использует 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 Рисунок 2
Поскольку это не похоже на «функцию», которую можно интегрировать, я бы использовал метод численного интегрирования. Я всегда неравнодушен к trapz
, которые используют « правило трапеции » для численного интегрирования.
Что-то вроде:
area = trapz(data);
должно быть достаточно.
Надеюсь, что это поможет,
Уилл