Адрес источника:GitHub.com/Вэй Жуйфэн/…
Цифровая обработка изображений относится к обработке, выполняемой компьютером. Когда дело доходит до цифровой обработки изображений, все будут думать, что в C++ есть много библиотек и алгоритмов, а MATLAB удобен, но с тех пор, как Canvas, JavaScript может выполнять операции над изображениями на уровне пикселей и даже напрямую обрабатывать необработанные двоичные данные изображений.
Получить данные и сохранить изображения
получить данные
использоватьfileReaderа такжеcanvasПолучить изображения с
<canvas id="myCanvas">抱歉,您的浏览器还不支持canvas。</canvas>
<input type="file" id="myFile" />
Когда пользователь выбирает изображение
file.onchange = function(event) {
const selectedFile = event.target.files[0];
const reader = new FileReader();
reader.onload = putImage2Canvas;
reader.readAsDataURL(selectedFile);
}
function putImage2Canvas(event) {
const img = new Image();
img.src = event.target.result;
img.onload = function(){
myCanvas.width = img.width;
myCanvas.height = img.height;
var context = myCanvas.getContext('2d');
context.drawImage(img, 0, 0);
const imgdata = context.getImageData(0, 0, img.width, img.height);
// 处理imgdata
}
}
Среди них объект ImageData хранит реальные пиксельные данные объекта холста, включая 3 свойства, доступные только для чтения: **width: **ширина изображения в пикселях **height:** Высота изображения в пикселях. **data: **Одномерный массив типа Uint8ClampedArray, содержащий целочисленные данные в формате RGBA в диапазоне от 0 до 255 (включая 255) **Связь:** длина массива Uint8ClampedArray = 4 * ширина * высота Данные для приложений цифровой обработки изображенийImageData.dataДанные
сохранить изображение
HTMLCanvasElementобеспечитьtoDataURLметод, этот метод очень полезен при сохранении изображений. Он возвращает ссылку на данные, содержащую формат представления изображения, заданный параметром типа. Формат канала передачи данных
data:[<mediatype>][;base64],<data>
mediatypeпредставляет собой строку типа MIME, например, "image/jpeg" для файлов изображений JPEG. Если опущено, по умолчаниюtext/plain;charset=US-ASCII
Вы можете загрузить его через атрибут загрузки тега a в HTML.
downloadFile(fileName, url) {
const aLink = document.createElement('a');
aLink.download = fileName;
aLink.href = url;
aLink.click();
}
// 下载图片
downloadFile(fileName, myCanvas.toDataURL());
точечная операция
Point Operation позволяет пользователям изменять диапазон оттенков серого, занимаемый данными изображения, который можно рассматривать какпиксель в пиксельоперация копирования. Если входное изображение, выходное изображение), точечная операция может быть выражена как:
в котором положитьНазываемая функцией преобразования оттенков серого, она описывает взаимосвязь преобразования между входным значением оттенков серого и выходным значением оттенков серого. Как только функция преобразования оттенков серого определена, операция точки полностью определена.
Общие операции точечных операций включают выравнивание оттенков серого, линейное преобразование, пороговое преобразование, преобразование окна и растяжение оттенков серого.
Гистограмма оттенков серого
Обзор
Гистограмма оттенков серого используется для подсчета количества или пропорции пикселей (от 0 до 255) в изображении в градациях серого (уровень), а ордината представляет количество или вероятность пикселей с каждым значением серого или уровнем серого, появляющимся на изображении.
код
/**
* 统计数据(针对灰度图像)
* @param data 原始数据
* @param strength 分份
* @returns {Array}
*/
function statistics(data, strength = 1) {
const statistArr = [];
for (let i = 0, len = data.length; i < len; i += 4) {
const key = Math.round(data[i] / strength);
statistArr[key] = statistArr[key] || 0;
statistArr[key]++;
}
return statistArr;
}
Распределение пикселей изображения можно увидеть на гистограмме.
Выравнивание гистограммы
Обзор
Все мы знаем, что если контрастность изображения больше, то картинка будет четкой и привлекающей внимание, а если контрастность будет мала, изображение будет казаться серым. Так называемый коэффициент контрастности — это отношение черного к белому на сером изображении, то есть градиент от черного к белому. Чем больше соотношение, тем больше уровней градиента от черного к белому и тем богаче цветопередача.
Выравнивание гистограммы — это метод использования гистограммы изображения для регулировки контраста в области обработки изображения. Цель состоит в том, чтобы значение каждого пикселя изображения имело одинаковую величину на изображении, что сделает слишком яркое или слишком темное изображение на заднем и переднем плане более четким.
Теоретические основы
Рассмотрим дискретное изображение {x} в градациях серого, пустьУказывает оттенки серогоКоличество вхождений, чтобы оттенки серого на изображении былиВероятность появления пикселя:
количество всех уровней серого в изображении (обычно 256),это количество всех пикселей в изображении,на самом деле значение пикселяГистограмма изображения, нормированная на.
поставить соответствуетКумулятивная функция распределения определяется как:
является кумулятивной нормализованной гистограммой изображения.
Мы создаем формупреобразование, для каждого значения в исходном изображении он создает,такКумулятивная функция вероятности может быть линеаризована во всех диапазонах значений, а формула преобразования определяется как:
для постоянного, 256 в обработке изображений.
БудуВнесите (3), чтобы получить:
Вычислить (3)(4), чтобы получить:
Формула 5 представляет собой соотношение между исходным пикселем и преобразованным пикселем.
код
/**
* 该函数用来对图像进行直方图均衡
* @param data
*/
function inteEqualize(data) {
// 灰度映射表
const bMap = new Array(256);
// 灰度映射表
const lCount = new Array(256);
for (let i = 0; i < 256; i++) {
// 清零
lCount[i] = 0;
}
// 计算各个灰度值的计数(只针对灰度图像)
for (let i = 0, len = data.length; i < len; i += 4) {
lCount[data[i]]++;
}
// 计算灰度映射表
for (let i = 0; i < 256; i++) {
let lTemp = 0;
for (let j = 0; j < i; j++) {
lTemp += lCount[j];
}
// 计算对应的新灰度值
bMap[i] = Math.round(lTemp * 255 / (data.length / 4));
}
// 赋值
for (let i = 0, len = data.length; i < len; i += 4) {
data[i] = bMap[data[i]];
data[i + 1] = bMap[data[i + 1]];
data[i + 2] = bMap[data[i + 2]];
}
}
Линейное преобразование оттенков серого
теоретические основы
Линейное преобразование градаций серого заключается в преобразовании градаций серого всех точек изображения в соответствии с функцией линейного преобразования градаций серого.является одномерной линейной функцией:
Уравнение преобразования оттенков серого:
Параметры в формуле- наклон линейной функции,является линейной функцией впересечение оси,представляет оттенки серого входного изображения,Представляет оттенки серого выходного изображения.
Изображения в градациях серого имеют следующие правила:
- когда, контраст выходного изображения увеличится, при f, контрастность выходного изображения будет снижена;
- когдаа такжеКогда он не равен 0, операция перемещает все пиксели вверх или вниз только при перемещении значения серого вверх или вниз, и эффект заключается в том, чтобы сделать все изображение темнее или ярче;
- если, темная область станет ярче, яркая область станет темнее, а операция точки завершает операцию дополнения изображения;
- если, выходное изображение совпадает с входным изображением;
- еслиКогда , оттенки серого выходного изображения просто инвертируются;
код
/**
* 该函数用来对图像灰度
* @param data
* @param fA 线性变换的斜率
* @param fB 线性变换的截距
*/
function linerTrans(data, fA, fB) {
for (let i = 0, len = data.length; i < len; i += 4) {
// 针对RGB三个进行转换
for (let j = 0; j < 3; j++) {
let fTemp = fA * data[i + j] + fB;
if (fTemp > 255) {
fTemp = 255;
} else if (fTemp < 0) {
fTemp = 0;
} else {
fTemp = Math.round(fTemp);
}
data[i + j] = fTemp;
}
}
}
пороговое преобразование оттенков серого
теоретические основы
Пороговое преобразование оттенков серого может преобразовать изображение в оттенках серого в черно-белое бинарное изображение. Пользователь заранее задает пороговое значение.Если значение серого пикселя на изображении меньше порогового значения, значение серого пикселя устанавливается равным 0, в противном случае — равным 255.
код
/**
* 该函数用来对图像进行阈值变换
* @param data
* @param bthre 阈值
*/
function thresholdTrans(data, bthre) {
for (let i = 0, len = data.length; i < len; i += 4) {
// 针对RGB三个进行转换
for (let j = 0; j < 3; j++) {
if (data[i + j] < bthre) {
data[i + j] = 0;
} else {
data[i + j] = 255;
}
}
}
}
Преобразование окна в градациях серого
теоретические основы
Преобразование окна в градациях серого определяет диапазон окна, а значение градаций серого в окне остается неизменным; значение градаций серого меньше нижнего предела окна напрямую устанавливается равным 0; значение градаций серого больше верхнего предела окна устанавливается напрямую до 255.
Выражение функции преобразования окна в градациях серого выглядит следующим образом:
В формулеОн представляет нижнюю часть окна,Представляет верхнюю границу окна.
Преобразование окна в градациях серого можно использовать для удаления светлого фона и темных объектов.
код
/**
* 该函数用来对图像进行窗口变换。只有在窗口范围内对灰度保持不变
* @param data
* @param bLow 下限
* @param bUp 上限
*/
function windowTrans(data, bLow, bUp) {
for (let i = 0, len = data.length; i < len; i += 4) {
// 针对RGB三个进行转换
for (let j = 0; j < 3; j++) {
if (data[i + j] < bLow) {
data[i + j] = 0;
} else if (data[i + j] > bUp) {
data[i + j] = 255;
}
}
}
}
Функция преобразования «Растяжка в градациях серого»
Растяжка в градациях серого чем-то похожа на линейное преобразование в градациях серого, за исключением того, что растяжение в градациях серого — это не полное линейное преобразование, а кусочно-линейное преобразование.
Выражение функции выглядит следующим образом:
Функция преобразования оттенков серого показана на рисунке:
код
/**
* 该函数用来对图像进行灰度拉伸
* 该函数的运算结果是将原图在x1和x2之间的灰度拉伸到y1和y2之间
* @param data
* @param bx1 灰度拉伸第一个点的X坐标
* @param by1 灰度拉伸第一个点的Y坐标
* @param bx2 灰度拉伸第二个点的X坐标
* @param by2 灰度拉伸第二个点的Y坐标
*/
function grayStretch(data, bx1, by1, bx2, by2) {
// 灰度映射表
const bMap = new Array(256);
for (let i = 0; i < bx1; i++) {
// 防止分母为0
if (bx1 > 0) {
// 线性变换
bMap[i] = Math.round(by1 * i / bx1);
} else {
bMap[i] = 0;
}
}
for (let i = bx1; i < bx2; i++) {
// 判断bx1是否等于bx2(防止分母为0)
if (bx2 !== bx1) {
bMap[i] = Math.round((by2 - by1) * (i - bx1) / (bx2 - bx1));
} else {
// 直接赋值为by1
bMap[i] = by1;
}
}
for (let i = bx2; i < 256; i++) {
// 判断bx2是否等于256(防止分母为0)
if (bx2 !== 255) {
// 线性变换
bMap[i] = by2 + Math.round((255 - by2) * (i - bx2) / (255 - bx2));
} else {
// 直接赋值为255
bMap[i] = 255;
}
}
for (let i = 0, len = data.length; i < len; i += 4) {
data[i] = bMap[data[i]];
data[i + 1] = bMap[data[i + 1]];
data[i + 2] = bMap[data[i + 2]];
}
}
Геометрическое преобразование изображений
Холст в HTML5 имеет полный интерфейс обработки изображений. При выполнении геометрического преобразования изображения мы можем напрямую использовать интерфейс холста. Ниже кратко перечислены несколько интерфейсов геометрического преобразования:
-
панорамирование изображения
context.translate(x, y);
-
Масштабирование изображения
context.scale(scalewidth, scaleheight);
-
зеркальное преобразование
canvasСпециального метода зеркального преобразования в , но не волнуйтесь, пока мы не касались операций на уровне пикселей. Сопутствующее содержание масштабирования изображения было представлено в предыдущем разделе, в котором говорилось оscalewidthа такжеscaleheightКогда абсолютное значение больше 1, оно увеличивается, а когда оно меньше 1, оно уменьшается, но его положительные и отрицательные значения не упоминаются.
content.translate(myCanvas.width/2, myCanvas.height/2); content.scale(-1, 1); content.translate(myCanvas.width/2, myCanvas.height/2); content.drawImage(img, 10, 10);
-
Поворот изображения
context.rotate(angle);
-
транспонирование изображения
canvasНе существует определенного метода транспонирования изображения, но мы можем использовать комбинацию поворота и зеркального отображения для достижения цели транспонирования изображения. Транспонирование изображения можно разделить на горизонтальное отражение и затем поворот на 90° по часовой стрелке или вертикальное отражение, а затем поворот на 90° против часовой стрелки. Затем мы используем поворот на 90° по часовой стрелке, а затем горизонтальное отражение, чтобы реализовать операцию транспонирования изображения.
context.translate(myCanvas.width/2, myCanvas.height/2); context.scale(-1, 1); context.rotate(90*Math.PI/180); context.translate(-myCanvas.width/2, -myCanvas.height/2); context.drawImage(img, 10, 10);
улучшение изображения
Улучшение изображения заключается в том, чтобы выделить интересующую часть изображения и ослабить его вторичную информацию, тем самым повысив удобочитаемость изображения. Обычные объективы имеют выступающий профиль цели, гасящий различные шумы.
Обычно существует два типа методов улучшения изображения: метод пространственной области и метод частотной области. Метод пространственной области в основном работает непосредственно со значением серого пикселей изображения в пространственной области. В этой главе представлен только метод пространственной области.
Методы улучшения изображения, такие как метод пространственной области, можно описать следующей формулой:
вэто изображение до обработки,представляет обработанное изображение,Пространственная арифметическая функция.
Коррекция изображения в оттенках серого
Коррекция оттенков серого изображения использует различные методы коррекции в соответствии с различными явлениями ухудшения качества изображения. Общие методы относятся к методам точечных операций.
Работа с шаблоном
Шаблон представляет собой квадрат матрицы. Операцию с шаблоном можно рассматривать как процесс взвешенного суммирования. Каждый пиксель в используемой области изображения умножается на каждый элемент в квадрате матрицы, а сумма всех произведений используется как центральный пиксель Новое значение представляет собой метод операции, часто используемый при цифровой обработке изображений. Сглаживание, увеличение резкости, истончение и обнаружение краев изображения используют операцию шаблона.
Например: общий алгоритм сглаживания состоит в том, чтобы сложить значение серого пикселя в исходном изображении и значения серого восьми соседних пикселей вокруг него, а затем использовать среднее значение (деленное на 9) в качестве нового изображения. значение оттенков серого пикселя. Это выражается следующим образом:
При использовании шаблона для обработки изображения обратите внимание на проблему с границей, поскольку при использовании шаблона для обработки границы будет сообщено об ошибке.Обычно используемые методы:
- Граничные пиксели игнорируются, т.е. обрабатываемые пиксели будут отбрасывать эти пиксели.
- Сохраните исходные граничные пиксели, то есть скопируйте граничные пиксели в обработанное изображение.
Общие шаблоны
-
фильтр нижних частот
-
фильтр верхних частот
-
Преобразование и обнаружение дифференциальных краев
-
Обнаружение края согласованного фильтра
-
обнаружение края
-
Обнаружение направления градиента
код
/**
* 模版操作
* @param data 数据
* @param lWidth 图像宽度
* @param lHeight 图像高度
* @param tempObj 模版数据
* @param tempObj.iTempW 模版宽度
* @param tempObj.iTempH 模版高度
* @param tempObj.iTempMX 模版中心元素X坐标
* @param tempObj.iTempMY 模版中心元素Y坐标
* @param tempObj.fpArray 模版数组
* @param tempObj.fCoef 模版系数
*/
function template(data, lWidth, lHeight, tempObj) {
const { iTempW, iTempH, iTempMX, iTempMY, fpArray, fCoef } = tempObj;
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
// 行(除去边缘几行)
for (let i = iTempMY; i < lHeight - iTempMY - 1; i++) {
// 列(除去边缘几列)
for (let j = iTempMX; j < lWidth - iTempMX - 1; j++) {
const count = (i * lWidth + j) * 4;
const fResult = [0, 0, 0];
for (let k = 0; k < iTempH; k++) {
for (let l = 0; l < iTempW; l++) {
const weight = fpArray[k * iTempW + l];
const y = i - iTempMY + k;
const x = j - iTempMX + l;
const key = (y * lWidth + x) * 4;
// 保存像素值
for (let i = 0; i < 3; i++) {
fResult[i] += dataInit[key + i] * weight;
}
}
}
for (let i = 0; i < 3; i++) {
// 乘上系数
fResult[i] *= fCoef;
// 取绝对值
fResult[i] = Math.abs(fResult[i]);
fResult[i] = fResult[i] > 255 ? 255 : Math.ceil(fResult[i]);
// 将修改后的值放回去
data[count + i] = fResult[i];
}
}
}
}
Обработка границы в коде заключается в сохранении исходных пикселей границы.
Гладкий и острый
Идея сглаживания заключается в удалении резко меняющихся точек за счет операции с одной точкой и несколькими окружающими точками, чтобы отфильтровать определенное количество шума, но при этом изображение имеет определенную степень размытия. шаблон фильтра нижних частот.
Цель повышения резкости — сделать размытые изображения более четкими. Размытие изображения вызвано усреднением или интегральной операцией изображения, поэтому обратные операции, такие как дифференциальные операции, могут выполняться над изображением, чтобы сделать изображение четким. С точки зрения спектра суть размытия изображения заключается в том, что его высокочастотные составляющие ослабляются, поэтому для очистки изображения можно использовать операцию высокочастотной фильтрации. Повышение резкости также усиливает шум изображения, поэтому, как правило, перед повышением резкости шум удаляется или уменьшается.
Заточка изображений обычно имеет два метода: вычисление и высокая проходная фильтрация. Способ фильтрации High Pass может относиться к режиму фильтра высокого передач. Размерные колебательные колебательные вводит лаплас Рис.
Градиентная резкость
Пусть образ будет,определениев точкувектор градиента вдля:
Градиент имеет два важных свойства:
Направление градиента находится в функцииВ направлении максимальной скорости изменения
Величина градиента используетсяозначает, что его значение равно:
Из этой формулы можно сделать вывод, что значение градиента равноВеличина, на которую единичное расстояние увеличивается в направлении максимальной скорости его изменения.
Для дискретного цифрового изображения приведенное выше уравнение можно переписать как:
Для удобства расчета можно также использовать следующую формулу приближенного расчета:
Этот метод градиента также известен как метод горизонтальной и вертикальной разницы, и есть еще один метод, который выполняет дифференциальный расчет крест-накрест, который называется градиентным методом Роберта:
Алгоритм абсолютной разности аппроксимируется следующим образом:
Поскольку градиент мал, когда изображение изменяется медленно, изображение будет выглядеть очень темным.Обычная практика заключается в том, чтобы задать пороговое значение,еслименьше порога, сохранить исходное значение серого без изменений; если оно больше или равно порогу, то задание:
Код алгоритма, основанный на методе горизонтальной и вертикальной разности, выглядит следующим образом:
/**
* 该函数用来对图像进行梯度锐化
* @param data 数据
* @param lWidth 宽度
* @param lHeight 高度
* @param bThre 阈值
*/
function gradSharp(data, lWidth, lHeight, bThre) {
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
for (let i = 0; i < lHeight - 1; i++) {
for (let j = 0; j < lWidth - 1; j++) {
const lpSrc = (i * lWidth + j) * 4;
const lpSrc1 = ((i + 1) * lWidth + j) * 4;
const lpSrc2 = (i * lWidth + j + 1) * 4;
for (let i = 0; i < 3; i++) {
const bTemp = Math.abs(dataInit[lpSrc + i] - dataInit[lpSrc1 + i]) +
Math.abs(dataInit[lpSrc + i] - dataInit[lpSrc2 + i]);
if (bTemp >= 255) {
data[lpSrc + i] = 255;
// 判断是否大于阈值,对于小于情况,灰度值不变
} else if (bTemp >= bThre) {
data[lpSrc + i] = bTemp;
}
}
}
}
}
Лапласовская заточка
Мы знаем, что дифференциал функции первого порядка описывает рост или уменьшение образа функции, а дифференциал второго порядка описывает скорость изменения образа, например резкое увеличение или уменьшение или мягкое увеличение или уменьшение. Операция Лапласа также является линейной комбинацией операции с частной производной и является изотропной линейной операцией.
Предполагатьявляется оператором Лапласа, то:
Для дискретных цифровых изображений, а его частная производная первого порядка:
Тогда его частная производная второго порядка:
Итак, оператор Лапласадля:
Для размытия изображения, вызванного явлением диффузии, вы можете использовать следующую формулу для увеличения резкости:
здесьЭто коэффициент, связанный с эффектом диффузии. Этот коэффициент разумен, еслиЕсли он слишком большой, край контура изображения выйдет за пределы; в противном случае, еслиЕсли он слишком мал, эффект резкости не будет очевиден.
если заказ, формула преобразования:
Таким образом можно получить шаблонную матрицу:
На самом деле, у нас есть другая форма с помощью широко используемого шаблона повышения резкости Лапласа:
Код в шаблоне ссылки на код.
медианный фильтр
принцип
Медианная фильтрация — это технология нелинейной цифровой фильтрации.Как правило, используется скользящее окно, содержащее нечетное число точек, а медианное значение значения серого каждой точки в окне используется для замены значения серого фиксированной точки (обычно центр окна). Для элементов с нечетными номерами медиана относится к среднему значению после сортировки по размеру, а для элементов с четными номерами медиана относится к среднему значению двух средних значений серого после сортировки.
Медианная фильтрация является распространенным этапом обработки изображений, и она особенно полезна для спеклов и шумов соли и перца.
код
/**
* 中值滤波
* @param data 数据
* @param lWidth 图像宽度
* @param lHeight 图像高度
* @param filterObj 模版数据
* @param filterObj.iFilterW 模版宽度
* @param filterObj.iFilterH 模版高度
* @param filterObj.iFilterMX 模版中心元素X坐标
* @param filterObj.iFilterMY 模版中心元素Y坐标
*/
function medianFilter(data, lWidth, lHeight, filterObj) {
const { iFilterW, iFilterH, iFilterMX, iFilterMY } = filterObj;
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
// 行(除去边缘几行)
for (let i = iFilterMY; i < lHeight - iFilterH - iFilterMY - 1; i++) {
for (let j = iFilterMX; j < lWidth - iFilterW - iFilterMX - 1; j++) {
const count = (i * lWidth + j) * 4;
const fResult = [[], [], []];
for (let k = 0; k < iFilterH; k++) {
for (let l = 0; l < iFilterW; l++) {
const y = i - iFilterMY + k;
const x = j - iFilterMX + l;
const key = (y * lWidth + x) * 4;
// 保存像素值
for (let i = 0; i < 3; i++) {
fResult[i].push(dataInit[key + i]);
}
}
}
// 将中值放回去
for (let w = 0; w < 3; w++) {
data[count + w] = getMedianNum(fResult[w]);
}
}
}
}
/**
* 将数组排序后获取中间的值
* @param bArray
* @returns {*|number}
*/
function getMedianNum(bArray) {
const len = bArray.length;
bArray.sort();
let bTemp = 0;
// 计算中值
if ((len % 2) > 0) {
bTemp = bArray[(len - 1) / 2];
} else {
bTemp = (bArray[len / 2] + bArray[len / 2 - 1]) / 2;
}
return bTemp;
}
export { medianFilter };
Морфология изображения
Теоретической основой морфологии является теория множеств. Математическая морфология предлагает уникальный набор преобразований и операций. Давайте взглянем на некоторые из самых основных математических морфологических операций.
для данного целевого изображенияи структурный элемент, представьте себеПереместите изображение. в каждом текущем местоположении,Возможны только три состояния:
- а такжени один не пуст
как показано на рисунке:
Описание первого случаяа такжеНаиболее актуальный; второй случай иллюстрируета такжене имеет значения, тогда как третий случай иллюстрируета такжеТолько частично связаны.
коррозия и расширение
принцип
Когда точка, удовлетворяющая условию 1Общий состав структурирующих элементов и максимальное связанное множество точек изображения, мы называем это множество точек какправильноКоррозия, при выполнении всех составляющих элементов точки Х условий 1 и 2, и максимальное связанное с ней множество точек изображения, назовем это множество точекправильнорасширение. Проще говоря, эрозию можно рассматривать каккаждый со структурирующим элементомконгруэнтное подмножествосжиматься до точек, расширение будетКаждая точкарасширяться до.
Операция эрозии и дилатации заключается в выполнении над изображением X заданной операции по заданному шаблону, как показано на рисунке:
код
Код представляет собой алгоритм эрозии и расширения бинарных изображений.
/**
* 说明:
* 该函数用于对图像进行腐蚀运算。
* 结构元素为水平方向或垂直方向的三个点,中间点位于原点;
* 或者由用户自己定义3*3的结构元素。
* 要求目标图像为只有0和255两个灰度值的灰度图像
* @param data 图像数据
* @param lWidth 原图像宽度(像素数)
* @param lHeight 原图像高度(像素数)
* @param nMode 腐蚀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素
* @param structure 自定义的3*3结构元素
*/
function erosionDIB(data, lWidth, lHeight, nMode, structure) {
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
if (nMode === 0) {
// 使用水平方向的结构元素进行腐蚀
for (let j = 0; j < lHeight; j++) {
// 由于使用1*3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
for (let i = 1; i < lWidth - 1; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
// 如果原图像中当前点自身或者左右如果有一个点不是黑色,则将目标图像中的当前点赋成白色
for (let n = 0; n < 3; n++) {
const pixel = lpSrc + n - 1;
data[lpSrc * 4 + k] = 0;
if (dataInit[pixel * 4 + k] === 255) {
data[lpSrc * 4 + k] = 255;
break;
}
}
}
}
}
} else if (nMode === 1) {
// 使用垂直方向的结构元素进行腐蚀
// 由于使用1*3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 0; i < lWidth; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
// 如果原图像中当前点自身或者左右如果有一个点不是黑色,则将目标图像中的当前点赋成白色
for (let n = 0; n < 3; n++) {
const pixel = (j + n - 1) * lWidth + i;
data[lpSrc * 4 + k] = 0;
if (dataInit[pixel * 4] === 255) {
data[lpSrc * 4 + k] = 255;
break;
}
}
}
}
}
} else {
// 由于使用3*3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素和最上边和最下边的两列元素
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 1; i < lWidth - 1; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
data[lpSrc * 4 + k] = 0;
// 如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,则将目标图像中的当前点赋成白色
for (let m = 0; m < 3; m++) {
for (let n = 0; n < 3; n++) {
if (structure[m][n] === -1) {
continue;
}
const pixel = lpSrc + ((2 - m) - 1) * lWidth + (n - 1);
if (dataInit[pixel * 4] === 255) {
data[lpSrc * 4 + k] = 255;
break;
}
}
}
}
}
}
}
}
/**
* 说明:
* 该函数用于对图像进行膨胀运算。
* 结构元素为水平方向或垂直方向的三个点,中间点位于原点;
* 或者由用户自己定义3*3的结构元素。
* 要求目标图像为只有0和255两个灰度值的灰度图像
* @param data 图像数据
* @param lWidth 原图像宽度(像素数)
* @param lHeight 原图像高度(像素数)
* @param nMode 腐蚀方式,0表示水平方向,1表示垂直方向,2表示自定义结构元素
* @param structure 自定义的3*3结构元素
*/
function dilationDIB(data, lWidth, lHeight, nMode, structure) {
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
if (nMode === 0) {
// 使用水平方向的结构元素进行腐蚀
for (let j = 0; j < lHeight; j++) {
// 由于使用1*3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素
for (let i = 1; i < lWidth - 1; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
// 如果原图像中当前点自身或者左右如果有一个点不是黑色,则将目标图像中的当前点赋成白色
for (let n = 0; n < 3; n++) {
const pixel = lpSrc + n - 1;
data[lpSrc * 4 + k] = 255;
if (dataInit[pixel * 4 + k] === 0) {
data[lpSrc * 4 + k] = 0;
break;
}
}
}
}
}
} else if (nMode === 1) {
// 使用垂直方向的结构元素进行腐蚀
// 由于使用1*3的结构元素,为防止越界,所以不处理最上边和最下边的两列像素
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 0; i < lWidth; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
// 如果原图像中当前点自身或者左右如果有一个点不是黑色,则将目标图像中的当前点赋成白色
for (let n = 0; n < 3; n++) {
const pixel = (j + n - 1) * lWidth + i;
data[lpSrc * 4 + k] = 255;
if (dataInit[pixel * 4] === 0) {
data[lpSrc * 4 + k] = 0;
break;
}
}
}
}
}
} else {
// 由于使用3*3的结构元素,为防止越界,所以不处理最左边和最右边的两列像素和最上边和最下边的两列元素
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 1; i < lWidth - 1; i++) {
const lpSrc = j * lWidth + i;
for (let k = 0; k < 3; k++) {
data[lpSrc * 4 + k] = 255;
// 如果原图像中对应结构元素中为黑色的那些点中有一个不是黑色,则将目标图像中的当前点赋成白色
for (let m = 0; m < 3; m++) {
for (let n = 0; n < 3; n++) {
if (structure[m][n] === -1) {
continue;
}
const pixel = lpSrc + ((2 - m) - 1) * lWidth + (n - 1);
if (dataInit[pixel * 4] === 0) {
data[lpSrc * 4 + k] = 0;
break;
}
}
}
}
}
}
}
}
Открытые и закрытые операции
Мы знаем, что коррозия — это процесс устранения граничных точек и сжатия границы внутрь, что можно использовать для устранения мелких и бессмысленных объектов. Расширение — это процесс слияния всех точек фона, соприкасающихся с объектом, с объектом для расширения границы наружу, что можно использовать для заполнения дыр в объекте.
Процесс эрозии, а затем расширения называется операцией открытия. Используется для устранения мелких объектов, разделения объектов в тонких точках и сглаживания границ более крупных объектов без существенного изменения их площади; процесс расширения с последующей эрозией называется операцией замыкания. Используется для заполнения небольших пустот в объектах, соединения соседних объектов и сглаживания их границ без существенного изменения их площади.
Открытая операция и закрытая операция представляют собой комбинацию эрозии и расширения, поэтому код может относиться к коду эрозии и расширения.
утонченность
Уточнение заключается в том, чтобы найти центральную ось или скелет фигуры или штриха и заменить фигуру или штрих его скелетом. При распознавании символов или понимании изображения предварительное уточнение обработанного изображения помогает выделить и уменьшить количество избыточной информации.
Ниже приведен конкретный алгоритм прореживания (алгоритм быстрого параллельного прореживания Чжана):
одно из изображенийобласти, обозначьте каждую точку именем, где P1 находится в центре. как показано на рисунке:
если(т.е. черные точки), если одновременно выполняются следующие четыре условия, удалить их.
вдаКоличество ненулевых соседей ,да,, , , когда p9 – последовательность, значения этих точек варьируются отприбытьколичество изменений.
Повторяйте этот шаг для каждой точки изображения, пока все точки не станут неустранимыми.
код
/**
* 说明:
* 该函数用于对图像进行细化运算
* 要求目标图像为只有0和255两个灰度值的灰度图像
* @param data 图像数据
* @param lWidth 原图像宽度(像素数)
* @param lHeight 原图像高度(像素数)
*/
function thinDIB(data, lWidth, lHeight) {
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
let bModified = true;
const neighBour = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
];
while (bModified) {
bModified = false;
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 1; i < lWidth - 1; i++) {
let bCondition1 = false;
let bCondition2 = false;
let bCondition3 = false;
let bCondition4 = false;
const lpSrc = j * lWidth + i;
// 如果原图像中当前点为白色,则跳过
if (dataInit[lpSrc * 4]) {
continue;
}
// 获取当前点相邻的3*3区域内像素值,0代表白色,1代表黑色
const bourLength = 3;
for (let m = 0; m < bourLength; m++) {
for (let n = 0; n < bourLength; n++) {
const pixel = lpSrc + ((2 - m) - 1) * lWidth + (n - 1);
neighBour[m][n] = (255 - dataInit[pixel * 4]) ? 1 : 0;
}
}
const borderArr = [neighBour[0][1], neighBour[0][0], neighBour[1][0], neighBour[2][0],
neighBour[2][1], neighBour[2][2], neighBour[1][2], neighBour[0][2]];
let nCount1 = 0;
let nCount2 = 0;
for (let i = 0, len = borderArr.length; i < len; i++) {
nCount1 += borderArr[i];
if (borderArr[i] === 0 && borderArr[(i + 1) % len] === 1) {
nCount2++;
}
}
// 判断 2<= NZ(P1)<=6
if (nCount1 >= 2 && nCount1 <= 6) {
bCondition1 = true;
}
// 判断Z0(P1) = 1
if (nCount2 === 1) {
bCondition2 = true;
}
// 判断P2*P4*P8=0
if (borderArr[0] * borderArr[2] * borderArr[6] === 0) {
bCondition3 = true;
}
// 判断P2*P4*P6=0
if (borderArr[0] * borderArr[2] * borderArr[4] === 0) {
bCondition4 = true;
}
for (let k = 0; k < 3; k++) {
if (bCondition1 && bCondition2 && bCondition3 && bCondition4) {
data[lpSrc * 4 + k] = 255;
bModified = true;
} else {
data[lpSrc * 4 + k] = 0;
}
}
}
}
if (bModified) {
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
}
}
}
Края, контуры и заливки
обнаружение края
Край изображения является самой основной характеристикой изображения, так называемый край относится к набору пикселей, вокруг которых происходит ступенчатое изменение оттенков серого пикселей или изменение крыши. Существует два типа краев: один называется ступенчатым краем, а значения серого пикселей с обеих сторон существенно различаются; другой называется краем крыши, который располагается по значению серого от возрастания к убыванию. Поворотный момент перемен.
Оператор обнаружения края обнаруживает каждый пиксель в окрестности и количественно определяет скорость изменения уровня серого, включая определение направления. Большинство используют методы свертки, основанные на масках производных по направлениям. Ниже приведены несколько часто используемых операторов обнаружения границ:
-
Оператор обнаружения края Робертса:
Оператор обнаружения ребер Робертса — это оператор, который использует локальные разностные операторы для поиска ребер. Его дают:
где f(x, y) — входное изображение с целочисленными координатами в пикселях, а операция извлечения квадратного корня делает процесс похожим на то, что происходит в зрительной системе человека.
-
Оператор Sobel Edge
Вышеупомянутые два ядра свертки образуют оператор ребра Собеля, каждая точка изображения свернута с двухъядерной дугой, обычно вертикальный край соответствует наибольшему воздействию, наибольшему влиянию на другой горизонтальный край. Максимум два моталки в качестве выходного бита в этой точке.
-
Краевой оператор Превитта
Вышеупомянутые два ядра свертки образуют оператор края Превитта.Как и метод, использующий оператор Собеля, каждая точка изображения свертывается с этими двумя ядрами, и максимальное значение берется в качестве вывода. Оператор Превитта также создает изображение величины края.
-
Краевой оператор Криша
Вышеупомянутые 8 ядер свертки образуют краевой оператор Кирша. Каждая точка изображения свернута с 8 масками, каждая из которых максимально реагирует на определенное направление края. Максимальное значение во всех 8 направлениях выводится как изображение величины края. Порядковый номер маски максимального отклика представляет собой номер направления фронта.
-
Оператор Гаусса-Лапласа
Оператор Лапласа — это оператор второй производной, который работает с двумерными функциями. Обычно используются следующие операторы Лапласа:
Сравнение операторов обнаружения границ
оператор | Сравнение преимуществ и недостатков |
---|---|
Roberts | Эффект обработки изображения лучше для изображений с крутым низким уровнем шума, но результатом использования оператора Робертса для выделения края является то, что край является относительно толстым, поэтому местоположение края очень точное. |
Sobel | Эффект обработки изображения лучше для градиента серого и более шумных изображений, а оператор Собеля более точен для позиционирования края. |
Prewit | Это лучше влияет на обработку изображений с градиентом оттенков серого и большим количеством шума. |
Kirsch | Это лучше влияет на обработку изображений с градиентом оттенков серого и большим количеством шума. |
Гаусс-Лаплас | Он может точно определить местонахождение ступенчатых краевых точек на изображении и очень чувствителен к шуму.При этом теряется часть информации о направлении края, что приводит к прерывистому обнаружению края. |
Извлечение контура и отслеживание контура
Цель извлечения контура и отслеживания контура состоит в том, чтобы получить внешние особенности контура изображения. Алгоритм извлечения контура бинарного изображения очень прост и состоит в том, чтобы удалить внутреннюю точку: если точка в исходном изображении черная, а все 8 соседних точек черные (точка в это время является внутренней точкой), тогда точка удаляется. Содержание морфологии заключается в использовании девятиточечного структурного элемента для эрозии исходного изображения, а затем вычитании размытого изображения из исходного изображения.
Сравнение изображений извлечения контура изображения:
Отслеживание контура заключается в отслеживании границы путем последовательного поиска граничных точек. Во-первых, ищите в порядке слева направо и снизу вверх, и первая найденная черная точка должна быть нижней левой граничной точкой, обозначенной как A. По крайней мере, один из его правых, верхних правых, верхних и верхних левых соседей является граничной точкой, обозначаемой как B. Начиная с B, найдите граничную точку C среди соседних точек в следующем порядке: правая, правая верхняя, верхняя, левая, левая верхняя, левая нижняя, нижняя и правая нижняя. Если С является точкой А, это означает, что она сделала круг и программа завершает работу, в противном случае продолжайте поиск от точки С до тех пор, пока не будет найдена точка А. Легко судить, является ли она граничной точкой: если ее четыре соседи не черные точки, то это граничная точка.
Этот метод требует оценки восьми точек вокруг каждого граничного пикселя, и объем вычислений относительно велик. Существует также руководство по отслеживанию:
Сначала найдите нижнюю левую граничную точку, как описано выше. Начните с этой граничной точки, предполагая, что все граничные точки были найдены по часовой стрелке вокруг всего изображения. Поскольку граница непрерывна, каждая граничная точка может быть представлена углом, который эта граничная точка образует с предыдущей граничной точкой. Поэтому можно использовать следующие критерии отслеживания: начиная с первой граничной точки, определить начальное направление поиска вдоль верхнего левого угла; если верхняя левая точка является черной точкой, она является граничной точкой, в противном случае она вращается против часовой стрелки на основе в направлении поиска 90 градусов, продолжайте поиск следующей черной точки таким же образом, пока она не вернется к исходной многограничной точке.
Принципиальная схема алгоритма отслеживания контура выглядит следующим образом:
семенная начинка
Алгоритм заполнения начального числа — это алгоритм в графике, который является операцией, обратной алгоритму выделения контура.
Алгоритм заполнения исходной точки сначала предполагает, что некоторая точка внутри замкнутого контура известна, а затем алгоритм начинает поиск точек, смежных с исходной точкой и внутри контура. Если соседняя точка не находится внутри контура, то достигнута граница контура, если соседняя точка находится внутри контура, то эта точка становится новой исходной точкой, и поиск продолжается.
Поток алгоритма выглядит следующим образом:
- Исходный пиксель помещается в стек;
- Когда стек не пуст, вытолкните пиксель из стека и установите для пикселя желаемое значение;
- Для каждого четырехсвязного или восьмисвязного пикселя, соседнего с текущим пикселем, проверьте две указанные выше части;
- Если тестируемый пиксель не был заполнен в области, поместите пиксель в стек
Для четырехсвязной области и восьмисвязной области на третьем шаге объяснение следующее:
Каждый пиксель в четырехсвязной области соединен в четырех направлениях по горизонтали и вертикали. Каждый пиксель в восьми связанных областях связан в горизонтальном, вертикальном и четырех диагональных направлениях.
Суммировать
В этом документе дается базовое объяснение обработки цифровых изображений во внешнем интерфейсе, в основном для получения данных изображения, сохранения изображений, операций с точками, геометрической обработки, улучшения изображения, цифровой морфологии и обнаружения краев.Извлечение контура сделало простой анализ и реализацию. Не существует алгоритма для проведения глубоких исследований.
Адрес источника:GitHub.com/Вэй Жуйфэн/…