|
Обработка изображений с использованием расширения процессора |
ри сохранении вещественных значений в памяти, значения с одинарной точностью сохраняются в памяти в 4 последовательных байтах. 128-битный режим доступа используется для 128-разрядной выборки из памяти, 128-разрядной пересылки между SSE регистрами с плавающей запятой и всеми логическими, распаковки и арифметическими командами. 32-битный режим доступа используется для 32_разрядной выборки из памяти, 32-разрядной пересылки между SSE регистрами с плавающей запятой и скалярными арифметическими командами.Таблица 2-2. Вещественные числа и кодирование NaNSIMD регистр состояния и управленияРегистр состояния и управления используется для установки флагов обнаружения арифметических исключений, флагов режимов обработки арифметических исключений, режима округления, режима flush-to-zero и для просмотра флага состояния. Содержимое этого регистра может быть загруженно с помощью инструкций LDMXCSR и FXRSTOR и сохранено в памяти с помощью инструкций STMXCSR и FXSAVE. Биты 0-5 (поле обнаружения исключений) содержат 6 флагов, которые служат признаками детектирования арифметических SIMD исключений с плавающей точкой (0-нет, 1-да). Исключение произойдет только после следующей команды SSE. Потоковое расширение SSE использует только один флаг исключения для каждой исключительной ситуации. Здесь не предоставляется возможность для уведомления об индивидуальных исключительных ситуациях внутри упакованных данных. В ситуации, когда происходит несколько идентичных исключительных ситуаций в одной инструкции, соответствующий флаг исключения обновляется и указывает, что хотя бы одно из этих условий произошло. По умолчанию эти флаги сбрасываются.Биты 7-12 (поле маскирования исключений) определяют, как обрабатываются обнаруженные исключения. Если флаг установлен, то соответствующее исключение маскировано и обрабатывается процессором, который формирует приемлемый результат (в соответствии с процедурой, установленной по умолчанию) и продолжает выполнение программы. Если флаг сброшен, то вызывается программный обработчик для этого исключения. По умолчанию флаги устанавливаются в 1, значит что все исключения маскированы.Биты 13-14 (RC) устанавливают режим округления результатов при выполнении SSE-команд над данными с плавающей точкой. По умолчанию устанавливается режим округление до ближайшего.Бит 15 (FZ) используется для включения режима “Flush To Zero”. По умолчанию бит 15 установлен в 0, что выключает режим “Flush To Zero”.Остальные биты регистра MXCSR (биты 16-31 и бит 6) определены как зарезервированные и установлены в 0; попытка записи не нулевых значений в эти биты, используя инструкцию FXRSTOR или LDMXCSR, вызовет исключение общего нарушения защиты (general protection exception).Поле управления округлениемПоле управления округлением (RC) регистра MXCSR (биты 13 и 14) управляют как округляется результат инструкции с плавающей точкой.Поддерживается четыре режима округления:· округление до ближайшего· до меньшего или равного· до большего или равного· и в сторону нуля (смотреть таблицу 2-3).Округление до ближайшего - режим по умолчанию и он подходит для большинства приложений. Он обеспечивает наиболее точный и статистически несмещенную оценку правильного результата.Таблица 2-3. Поле управления округлением (RC)|
Режим округления | Установка полей RC | Описание | | Округление до ближайшего | 00B | Результатом округления берется наилучшее приближение до точного результата. Если два значения одинаково близки к точному результату, то берется четное значение (то есть, то значение у которого наименьший значащий разряд установлен в ноль) | | Округление до меньшего или равного (в сторону -?) | 01B | Результат округления ближайшее, но не больше чем точное решение. | | Округление до большего или равного (в сторону +?) | 10B | Результат округления ближайшее, но не меньше чем точное решение. | | Округление в сторону нуля (усечение) | 11B | Результат округления ближайшее, но не больше чем абсолютное значение точного решения. | | | Команды Потокового Расширения SIMDПотоковое Расширение SIMD состоит из 70 команд, сгруппированных в следующие категории:· Команды копирования данных· Арифметические команды· Команды сравнения · Команды преобразования типов данных· Логические команды· Дополнительные целочисленные SIMD-команды· Команды перестановки· Команды управления состоянием· Команды управления кэшированиемОперанды командПараллельные операции, как правило, действуют одновременно на все четыре 32-разрядных элемента данных в каждом из 128-разрядных операндов В именах команд, выполняющих параллельные операции, присутствует суффикс ps. Например, команда addps складывает 4 пары элементов данных и записывает полученные 4 суммы в соответствующие элементы первого операнда. Скалярные операции действуют на младшие (занимающие разряды 0-31) элементы данных двух операндов Остальные три элемента данных в выходном операнде не изменяются (исключение составляет команда скалярного копирования movss). В имени команд, выполняющих скалярные операции, присутствует суффикс ss (например, команда addss). Большинство команд имеют два операнда. Данные, содержащиеся в первом операнде, могут использоваться командой, а после ее выполнения, как правило, замещаются результатами. Данные во втором операнде используются в команде и после ее выполнения не изменяются. Далее в тексте входным называется второй операнд, а выходным - первый.Для всех команд адрес операнда в памяти должен быть выровнен по 16-байтной границе, кроме не выровненных команд сохранения и загрузки.Пример программы с использованием SSEПрограмма выполняет изменение значения цветовых составляющих каждого пикселя картинки (загружаемой с жесткого диска) для применения эффекта размытия.1. Изображение загружается (посредством диалогового окна) в компоненту «TImage».2. (после выбора пунктов «операции - Размытие Г.») Проверяется на соответствие формату 24 бита на пиксель.3. В специальном диалоговом окне, вводится опции (радиус зерна размытия), и запускается обработка изображения.4. Рассчитывается зерно размытия картинки по установленным параметрам, где производится расчет (списка весов) в несколько этапов.5. выделяется память для обработки изображения попиксельно, а также для обработки строк.7. копируется изображение в память ЭВМ.8. построчно производим эффект гауссово размытия к цветовым составляющим каждого пикселя.9. теперь каждую колонку с помощью созданного списка весов создаем эффект размытия.10. обработанные данные записываются в результативный компонент «TImage».11. освобождается выделенная память для скопированного изображения и обработки строк.12. (по выбору пункта «операции - сохранить» на вкладке «результат») данные результативного изображения сохраняются в файл.Листинг программыconstMaxKernelSize = 64;delay_names = 'миллисекунд';//for imagePRGBTriple = ^TPxlC;TPxlC = record//TPxlCb:byte;g:byte;r:byte;end;PRow = ^TRow; //массив картинкиTRow = array[0..1000000] of TPxlC;PPRows = ^TPRows; //массив строки пикселейTPRows = array[0..1000000] of PRow;TKernelSize = 1..MaxKernelSize;TKernel = record //зерноSize: TKernelSize; //размер зернаWeights: array[-(MaxKernelSize-1)..MaxKernelSize] of single;end;TXMMSingle = array[0..3] of Single;//массив для SSETXMMArrByte = array[0..15] of byte;//массив пикселейTXMMRsByte = recorditem:TXMMArrByte;end;TSSERegLines = array[0..5] of TXMMRsByte;//основная процелура размытияprocedure GBlur(theBitmap: TBitmap; radius: double; withSSE:boolean); varfrm_img: Tfrm_img;implementationuses DateUtils, optscopyimg, optsblurimg;{$R *.dfm}constMAX_imageSize = 65535;//построение зерна (списка весов) размытия (без SSE)//MakeGaussianKernel noSSE-----------------------------------------------------procedure MakeGaussianKernel(var K: TKernel; radius: double;MaxData, DataGranularity: double);//Делаем K (гауссово зерно) со среднеквадратичным отклонением = radius.//Для текущего приложения мы устанавливаем переменные MaxData = 255,//DataGranularity = 1. Теперь в процедуре установим значение//K.Size так, что при использовании K мы будем игнорировать Weights (вес)//с наименее возможными значениями. (Малый размер нам на пользу,//поскольку время выполнения напрямую зависит от//значения K.Size.)varj: integer;temp, delta: double;KernelSize: TKernelSize;a,b:smallint;begin//получили строку весов (зерна)for j:=Low(K.Weights) to High(K.Weights) do begintemp := j / radius;K.Weights[j] := exp(-(temp * temp) / 2);end;//делаем так, чтобы sum(Weights) = 1:temp:=0;for j := Low(K.Weights) to High(K.Weights) dotemp := temp + K.Weights[j];//все сумировалиfor j := Low(K.Weights) to High(K.Weights) doK.Weights[j] := K.Weights[j] / temp;//делим каждое на сумму (нормирование)//теперь отбрасываем (или делаем отметку "игнорировать"//для переменной Size) данные, имеющие относительно небольшое значение -//это важно, в противном случае смазавание происходим с малым радиусом и//той области, которая "захватывается" большим радиусом...KernelSize := MaxKernelSize;delta := DataGranularity / (2 * MaxData);temp := 0;while (temp < delta) and (KernelSize > 1) dobegintemp := temp + 2 * K.Weights[KernelSize];dec(KernelSize);end;//выравниваниеK.Size := KernelSize;//теперь для корректности возвращаемого результата проводим ту же//операцию с K.Size, так, чтобы сумма всех данных была равна единице:temp := 0;for j := -K.Size to K.Size dotemp := temp + K.Weights[j];//for j := -K.Size to K.Size doK.Weights[j] := K.Weights[j] / temp;//end;//построение зерна (списка весов) размытия с SSE//MakeGaussianKernel SSE-------------------------------------------------------procedure MakeGaussianKernelSSE(var K: TKernel; radius: double;MaxData, DataGranularity: double);//Делаем K (гауссово зерно) со среднеквадратичным отклонением = radius.//Для текущего приложения мы устанавливаем переменные MaxData = 255,//DataGranularity = 1. Теперь в процедуре установим значение//K.Size так, что при использовании K мы будем игнорировать Weights (вес)//с наименее возможными значениями. (Малый размер нам на пользу,//поскольку время выполнения напрямую зависит от//значения K.Size.)constnmax=3;varj: integer;temp, delta: double;KernelSize: TKernelSize;xmm_n,xmm_r,xmm_a:TXMMSingle;_low,_high,na:smallint;begin_low:=Low(K.Weights);_high:=High(K.Weights);j:=_low;for na:=0 to nmax do xmm_a[na]:=2;//константа 2for na:=0 to nmax do xmm_r[na]:=radius;//радиусasmpush eaxpush ebxpush ecxpush edxmovups xmm0,xmm_a//2 в SSEmovups xmm1,xmm_r//радиус в SSEend;while (j<=_high) do beginfor na:=0 to nmax doif ((j+na)<=_high) thenxmm_n[na]:=j+naelse break;//копирование простое и передача не дает оптимизации в SSEasmmovups xmm2,xmm_n //jdivps xmm2,xmm1 //j/radiusmovups xmm_n,xmm2mulps xmm2,xmm2 //temp^2movups xmm_n,xmm2divps xmm2,xmm0 //temp*temp/2movups xmm_n,xmm2end;//asmfor na:=0 to nmax do beginif (j<=_high) thenK.Weights[j]:=exp(-xmm_n[na])else break;inc(j);end;//forend;//while//получили строку весов (зерна)//делаем так, чтобы sum(Weights) = 1:temp:=0;for j := Low(K.Weights) to High(K.Weights) dotemp := temp + K.Weights[j];//все сумировалиfor j := Low(K.Weights) to High(K.Weights) doK.Weights[j] := K.Weights[j] / temp;//делим каждое на сумму (нормирование)for na:=0 to nmax do xmm_n[na]:=temp;asmmovups xmm0,xmm_n;end;j:=_low;while (j<=_high) do beginfor na:=0 to nmax do beginif ((j+na)<=_high) thenxmm_n[na]:=K.Weights[j+na]else break;end;//forasmmovups xmm1,xmm_ndivps xmm1,xmm0//K.Weights[j]/tempmovups xmm_n,xmm1end;for na:=0 to nmax do beginif (j<=_high) thenK.Weights[j]:=xmm_n[na]else break; inc(j);end;end;//while//отбрасываем (или делаем отметку "игнорировать"//для переменной Size) данные, имеющие относительно небольшое значение -//это важно, в противном случае смазавание происходим с малым радиусом и//той области, которая "захватывается" большим радиусом...KernelSize := MaxKernelSize;delta := DataGranularity / (2 * MaxData);temp := 0;while (temp < delta) and (KernelSize > 1) dobegintemp := temp + 2 * K.Weights[KernelSize];dec(KernelSize);end;//выравниваниеK.Size := KernelSize;//для корректности возвращаемого результата проводим ту же//операцию с K.Size, так, чтобы сумма всех данных была равна единице:temp := 0;for j := -K.Size to K.Size dotemp := temp + K.Weights[j];for na:=0 to nmax do xmm_n[na]:=temp;asmmovups xmm0,xmm_n;end;j:=_low;while (j<=_high) do beginfor na:=0 to nmax do beginif ((j+na)<=_high) thenxmm_n[na]:=K.Weights[j+na]else break;end;//forasmmovups xmm1,xmm_n
Страницы: 1, 2, 3
|
|
|
© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент. |
|
|