УДК 681.3.06 У912
КАФЕДРА МАТЕМАТИЧЕСКОГО ОБЕСПЕЧЕНИЯ И ПРИМЕНЕНИЯ ЭВМ
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕД...
546 downloads
546 Views
2MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
УДК 681.3.06 У912
КАФЕДРА МАТЕМАТИЧЕСКОГО ОБЕСПЕЧЕНИЯ И ПРИМЕНЕНИЯ ЭВМ
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ Государственное образовательное учреждение высшего профессионального образования "Южный федеральный университет"
Технологический институт Южного федерального университета в г.Таганроге Работа выполнена в соответствии с Программой развития Южного федерального университета на 2007-2010гг.
Н.Ш. Хусаинов Руководство к набору лабораторных работ на тему КОДИРОВ АНИЕ ИЗОБРА ЖЕ НИЙ С ИСПОЛЬ ЗОВА НИЕМ ПА КЕТ А MA TLAB по курсу "Теория кодирования информации"
Для студентов специальностей 230105 – Программное обеспечение вычислительной техники и автоматизированных систем 010503 – Математическое обеспечение и администрирование информационных систем Таганрог 2008
УДК 681.3.06 (076.5) + 681.325.5. (076.5)
Хусаинов Н.Ш. Руководство к набору лабораторных работ "Кодирование изображений с использованием пакета MATLAB" по дисциплине “Теория кодирования информации".– Таганрог: ТТИ ЮФУ, 2008. 60с.
Руководство включает две лабораторных работы. Первая нацелена на знакомство со средой MATLAB, приобретение базовых практических навыков работы с оболочкой пакета, изучение принципов обработки данных и построения программ на языке MATLAB. Кратко приводятся поддерживаемые типы данных, иерархия графических объектов и объектов пользовательского интерфейса, особенности выполнения вычислительных операций над данными, представляемыми в виде матриц. Вторая лабораторная работа посвящена разработке программы эффективного кодирования изображений. Организация пользовательского интерфейса и выполнение процедур кодирования и декодирования данных проиллюстрированы на приведенном примере программы на языке MATLAB. Приведены варианты задания для выполнения лабораторной работы. Пособие предназначено для студентов специальностей 220400, 351500, изучающих курс "Теория кодирования информации". Представляет интерес для инженеров, разработчиков и программистов в области систем обработки и кодирования текстовой, аудио- и визуальной информации.
© Технологический институт Южного федерального университета в г.Таганроге, 2008г. © Н.Ш.Хусаинов, 2008г.
2
СОДЕРЖАНИЕ
Лабораторная работа 1. Выполнение базовых вычислительных операций в среде MATLAB ......... Введение ......................................................................................................................................................... Состав интегрированной среды MATLAB ..................................................................................................... Краткие сведения об интерфейсе среды MATLAB ...................................................................................... Разработка пользовательского интерфейса для программ на языке MATLAB ........................................ Основы программирования на языке MATLAB ........................................................................................... Примеры реализации простейших алгоритмов обработки векторных и матричных данных средствами MATLAB ....................................................................................................................................... Способы оценки производительности и повышения эффективности программ на языке MATLAB ..... Вопросы для самопроверки .......................................................................................................................... Контрольные задания .................................................................................................................................... Список использованных источников к лабораторной работе № 1 ........................................................... Лабораторная работа 2. Реализация и исследование алгоритма компрессии изображений ........... Основные требования к выполнению работы ............................................................................................ Общие требования к содержанию отчета по лабораторной работе ........................................................ Пример. Разработка программа кодирования изображения по алгоритму JPEG ................................... Задания на лабораторную работу ................................................................................................................
3
ЛАБОРАТОРНАЯ РАБОТА 1. ВЫПОЛНЕНИЕ БАЗОВЫХ ВЫЧИСЛИТЕЛЬНЫХ ОПЕРАЦИЙ В СРЕДЕ MATLAB Цель работы – знакомство со средой MATLAB, изучение основных принципов организации вычислений. Основными задачами, стоящими при выполнении данной лабораторной работы, являются: - изучение состава интегрированной среды MATLAB и приобретение навыков работы с командным окном, рабочим пространством, текстовым редактором; - выполнение простейших операций по созданию, инициализации и преобразованиям матриц и векторов, доступа к элементам массивов средствами языка MATLAB; - знакомство с иерархией классов вычислительных объектов (типов данных) и графических объектов MATLAB; - организация программных конструкций с использованием операторов управления программой, оформление модулей MATLAB в виде файлов-сценариев и файлов-функций; - знакомство со способами оценки производительности программного кода в среде MATLAB и методами повышения эффективности программ.
Введение MATLAB (MATrix LABoratory) – интегрированная среда, объединяющая в себе средства для численных расчетов, моделирования, графические возможности и встроенный язык программирования высокого уровня MATLAB. Первоначальной целью при создании MATLAB было обеспечение доступа к программным библиотекам LINPACK и EISPACK, которые были написаны на Фортране и являлись на тот момент самыми современными средствами матричных вычислений. Собственно, язык программирования MATLAB был разработан Кливом Моулером (Cleve Moler) в конце 1970-х годов, когда он был деканом факультета компьютерных наук в Университете Нью-Мексико. Целью разработки служила задача дать студентам факультета возможность использования библиотек LINPACK и EISPACK без необходимости изучения Фортрана. Вскоре новый язык распространился среди других университетов и был с большим интересом встречен учёными, работающими в области прикладной математики. В 1984г. Клив Моулер вместе с инженерами Стивом Бангертом (Steve Bangert) и Джоном Литтлом (John N. (Jack) Little) основали компанию "The MathWorks" с целью "перенести" средства и языки математического и технического программирования, созданные к тому времени для суперкомпьютеров, на персональные компьютеры, сделав их коммерчески выгодным проектом. Первые 10 копий MATLAB (переведенного к тому времени с Фортрана на Си) были приобретены Масачусетским технологическим институтом по цене 500 долларов за экземпляр. Последующие версии MATLAB вышли в 1987 (MATLAB 2.0) и в 1991 (MATLAB 4.0) годах соответственно. В состав интегрированной среды MATLAB 4.0 был включен пакет Simulink (называвшийся сначала 4
SIMULAB), предназначенный для изучения и моделирования динамических систем, а также добавлены средства для визуализации данных и результатов расчетов [1]. На сегодняшний день MATLAB насчитывает более 1 млн. пользователей. Основными покупателями пакета являются компании, занятые высокотехнологичными разработками, научноисследовательские центры, финансовые организации и, конечно же, университеты [2]. MATLAB используется во множестве областей, среди которых обработка сигналов и изображений, проектирование систем управления и связи, финансовые расчеты и медицинские исследования. Его открытая архитектура делает возможным использование MATLAB и сопутствующих продуктов для исследования данных и создания собственных инструментов, использующих функциональные возможности MATLAB *3]. Сегодня MATLAB – платформонезависимый высокоуровневый язык для технических вычислений и интерактивная среда для разработки алгоритмов, численных вычислений, анализа и визуализации данных. MATLAB находит применение для самого широкого спектра приложений, включая обработки сигналов и изображений, связь, системы управления, тестирование оборудования, финансовые расчеты и медицинские исследования. Наборы дополнительных инструментов (toolboxes) расширяют возможности среды MATLAB и позволяют решать конкретные практические задачи. Кроме того, MATLAB также предоставляет возможности по интегрированию разработанных алгоритмов и программ с внешними приложениями и языками программирования (Microsoft Excel, .NET, COM, C/C++, Java) [3].
Состав интегрированной среды MATLAB Базовыми компонентами среды MATLAB являются [4] 1) интегрированная среда MATLAB, которая включает пять составляющих: - среда разработки (рабочий стол, окно команд, окно истории, рабочее пространство, редактор, отладчик, система помощи); библиотека базовых математических функций (от элементарных, типа сложения/вычитания, до более сложных, например, вычисление обратной матрицы или реализация быстрого преобразования Фурье); - язык MATLAB (высокоуровневый язык программирования, ориентированный на обработку векторов/матриц и содержащий большинство стандартных конструкций современных языков программирования, в том числе объектно-ориентированных); - подсистема графики (содержит высокоуровневые функции для отображения двух- и трехмерных данных, графиков, изображений, видео, анимации, деловой графики и низкоуровневые функции, позволяющие разработать собственный графический интерфейс приложения); - программный интерфейс MATLAB API (библиотека, позволяющая писать программы на языках С/С++, которые могут затем взаимодействовать с MATLAB. Библиотека содержит средства для вызова динамических подпрограмм (ddl) из MATLAB, вызова функций MATLAB для выполнения вычислений, чтения/записи данных в рабочем пространстве и файлах данных MATLAB. 5
Важная роль в MATLAB отводится коллекциям специализированных функций (Toolboxes), которые позволяют решать частные классы задач. 2) пакет моделирования Simulink – интерактивная среда для моделирования, имитации и анализа динамических систем в самых разных прикладных областях. Она позволяет проектировать модели на основе блоков, моделировать поведение системы, оценивать ее производительность и уточнять модель по результатам оценок. Основное предназначение Simulink – описание динамических систем, поведение которых можно представить как функцию от времени. Simulink глубоко интегрирован с MATLAB, что обеспечивает разработчику непосредственный доступ ко всем средствам обработки и анализа данных MATLAB. Особое значение при создании моделей имеет библиотека проблемно-ориентированных наборов блоков (Blocksets), реализующих специфичные для той или иной области алгоритмы обработки. 3) пакет Stateflow – интерактивный инструмент проектирования для создания и моделирования систем на основе событийного подхода. Используя предоставляемые средства разработчик может описывать поведение исследуемой системы как цепочку правил "если-то". Основой построения и исследования моделей в среде Stateflow является теория конечных автоматов. Совместное использование Simulink и Stateflow позволяет описать логику функционирования и создать виртуальный прототип практически любой системы. Множество входящих в MATLAB дополнительных средств (всего около 100 пакетов) по своему назначению можно разбить на следующие категории: - организация параллельных вычислений на нескольких ЭВМ локальной сети, организованных в вычислительный кластер), где установлен MATLAB с соответствующими пакетами (Parallel Computing Toolbox, MATLAB Distributed Computing Server); - математические вычисления и решение оптимизационных задач (Optimization Toolbox, Symbolic Math Toolbox, Partial Differential Equation Toolbox и др.); - статистическая обработка и анализ данных (Statistics Toolbox, Neural Network Toolbox, Spline Toolbox и др.); - проектирование, анализ систем управления, моделирование систем управления (Control System Toolbox, Robust Control Toolbox, Aerospace Toolbox, Simulink Control Design, Simulink Parameter Estimation, Aerospace Blockset и др.); - обработка сигналов и связь, моделирование систем связи и обработки сигналов (Signal Processing Toolbox, Communications Toolbox, Filter Design Toolbox, Wavelet Toolbox, Fixed-Point Toolbox, RF Toolbox , Signal Processing Blockset, Communications Blockset, Video and Image Processing Blockset и др.); - обработка изображений (Image Processing Toolbox, Mapping Toolbox и др.); - измерения и тестирование (Data Acquisition Toolbox, Instrument Control Toolbox и др.); - вычислительная биология (Bioinformatics Toolbox, SimBiology); - финансовое моделирование и анализ (Financial Toolbox, Fixed-Income Toolbox, Datafeed Toolbox и др.); - компьютерная графика (Virtual Reality Toolbox, Gauges Blockset); - моделирование физических процессов (Simscape, SimMechanics, SimPowerSystems, SimElectronics и др.); 6
- разработка приложений (MATLAB Compiler, Spreadsheet Link EX (for Microsoft Excel), MATLAB Builder NE (for Microsoft .NET Framework и др.); - генерация кода для выполнения в других исполнительных средах (Real-Time Workshop, Real-Time Embedded Coder и др.); - "быстрое" моделирование на целевой платформе (xPC Target, Real-Time Windows Target, Target Support Package for TC6 (for TI's C6000 DPP), Embedded IDE Link VS (for Analog Devices VisualDSP++) и др.); - работа с базами данных и генерация отчетов (Database Toolbox, MATLAB Report Generator); - верификация, валидация и тестирование (Simulink Verification and Validation, SystemTest, PolySpace Code Verification Products).
Краткие сведения об интерфейсе среды MATLAB При запуске MATLAB на экране появляется главное окно программы – рабочий стол, содержащий инструменты для работы с файлами (Current Directory), переменными рабочей области (Workspace), интерактивного выполнения команд (Command Window), окна истории команд (Command History), главного меню, панели инструментов, панели ссылок (Shortcuts) и кнопки запуска "Start" (аналогичной по своему функциональному назначению кнопке "Start" в ОС Windows) – как показано на рисунке 1.1.
Рисунок 1.1 – Рабочий стол MATLAB сразу после запуска приложения Одним из основных достоинств MATLAB является то, что для работы пользователю достаточно знать о нем ровно столько, сколько требует решаемая задача *5+. Если задача требует 7
использования каких-либо специальных инструментов, то пользователю предоставляется в распоряжение практически универсальный язык объектно-ориентированного программирования в сочетании с интерактивными средствами отладки создаваемых программ. А в простейшем случае MATLAB может сыграть роль простого калькулятора или средства для визуализации значений переменных или файлов, как показано на рисунке 1.2.
Рисунок 1.2 – Отображение значения переменной y, содержащей отсчеты звукового файла, в редакторе переменных (Variable Editor) и в виде графика Выполнять любые команды и функции MATLAB можно посредством окна Command Window рабочего стола MATLAB. Однако при написании более сложных программ, которые хранятся в mфайлах, целесообразно пользоваться встроенным редактором среды MATLAB (см. рисунок 1.3). Редактор MATLAB обладает мощными возможностями для написания, отладки и анализа программного кода. Средства, облегчающие набор программы и контроль синтаксиса стандартны для современных средств разработки программ. Дополнительным средством, которое автоматически проверяет фрагменты программы на предмет наличия потенциальных ошибок и оценки эффективности выполнения, является средство анализа M-Lint Code Check. Для повышения эффективности отладки и анализа программ кроме использования стандартных средств (условные и безусловные точки останова, просмотр значений переменных, профилирование) может использоваться механизм "быстрого" выполнения фрагмента программы Rapid Code Iteration Using Cells. Он позволяет выполнить оформленный специальным образом фрагмент, не выполняя остальной код программы. Разбив всю программу на такие фрагменты (называемые "ячейками" (Cells) кода), можно последовательно выполнять отладку программу, не прибегая к использованию точек останова. 8
Рисунок 1.3 – Окно редактора m-файлов среды MATLAB Для разработки пользовательского интерфейса (если это необходимо для решаемой задачи) MATLAB содержит инструмент GUIDE, вызываемый из главного меню MATLAB (кнопка Start) и позволяющий создавать экранные формы с набором стандартных элементов управления (кнопка, текстовая метка, поле для ввода, список, таблица, кнопки для выбора, поле для отображения графики и др.). Поля, связанные с каждым элементом управления и самой формой, можно редактировать с помощью Property Inspector. Описание формы и элементов управления хранится в файле с расширением ".fig". По аналогии с традиционными языками высокого уровня для каждой формы MATLAB автоматически генерирует m-файл с тем же именем, в котором находятся "главная" функция, отвечающая за прорисовку экранной формы, а также callback-функции, отвечающие за обработку событий, генерируемых элементами управления на форме. Подробное описание среды разработки MATLAB, оконного интерфейса и возможностей редактора приведены в *6,7]. В MATLAB используются несколько стандартных расширений файлов: - m-файлы (с расширением .m) – файлы, содержащие тексты программ на языке MATLAB. Есть два типа m-файлов: файлы-сценарии и файлы-функции. Файл-сценарий, именуемый также Script-файлом, является просто записью серии команд без входных и выходных параметров. Файлфункция содержит входные и выходные параметры, использует аппарат локальных переменных и поэтому является типичным объектом языка программирования системы MATLAB и полноценным модулем с точки зрения структурного программирования; - fig-файлы – файлы с описанием оконных форм (Figure) пользовательского интерфейса, обычно используются в программах на MATLAB; - mdl-файлы – файлы моделей Simulink; 9
- p-файлы – промежуточные файлы, содержащие скомпилированный код процедур MATLAB. Использование p-файлов обычно существенно повышение быстродействие по сравнению с выполнением (интерпретированием) m-файлов и позволяет защитить от несанкционированного доступа содержание программного кода; - mat-файлы – файлы, содержащие данные в двоичном коде (обычно значения каких-либо переменных), доступ к которым возможен из командного окна MATLAB либо с помощью специальных средств Simulink. Подробное описание формата mat-файла приведено в *8].
Разработка пользовательского интерфейса для программ на языке MATLAB Графический интерфейс пользователя (Graphical User Interface, GUI) предоставляет пользователю возможность интерактивной обработки данных в приложении посредством оконной формы. Основными элементами управления GUI на форме являются меню, панель инструментов, кнопки различных типов, списки и т.д. GUI может отображать данные в виде таблиц и графиков или изображений.
Разработка пользовательского интерфейса средствами GUIDE Для создания элементов пользовательского интерфейса используется встроенная в MATLAB оболочка GUIDE, которая в интерактивном режиме позволяет добавлять на форму элементы управления, контролировать и изменять их размер, порядок, выравнивание. При первом сохранении макета экранной формы GUIDE автоматически генерирует m-файл, содержащий код инициализации формы, а также процедуры для вызова, визуализации и закрытия экранной формы. Пример экранной формы, созданной в GUIDE, приведен на рисунке 1.4. По аналогии с другими современными средами разработки программ, управление полями элементов формы в GUIDE осуществляется с использованием окна редактора свойств (Inspector). GUIDE также выполняет генерацию шаблонов (заголовков и минимума кода) для callback-процедур по необходимому событию. Подробнее средства создания пользовательского интерфейса в MATLAB средствами GUIDE описаны в *9+.
10
Рисунок 1.4 – Окно GUIDE с созданной экранной формой
Виды графических объектов MATLAB Иерархия графических объектов MATLAB приведена на рисунке 1.5. Основным объектом пользовательского интерфейса в MATLAB является оконная форма (Figure), которая может содержать как объекты пользовательского интерфейса (UI objects), так и "рисованные" графические объекты. Объект Figure, в свою очередь является потомком объекта Root, события и свойства которого позволяют работать с некоторыми глобальными установками MATLAB.
11
Root
Figure
UI Objects
UI Toolbar Object
UI Control Objects
UI Menu Object
Primary Objects
Container Objects
ActiveX Object
checkbox edit
uipanel uibuttongroup
Axes
UI ContextMenu Object
Core Objects
image
Hidden Annotation Axes
Plot Objects
Group Objects
areaseries
light
barseries
line
contourgroup
patch rectangle
Annotation Objects
errorbarseries lineseries
text
surface
quivergroup
uitable
text
scattergroup
listbox
stairseries
popupmenu
stemseries
pushbutton
surfaceplot
radiobutton togglebutton slider
Рисунок 1.5 – Иерархия графических объектов MATLAB Графические объекты MATLAB можно разделить на два больших подмножества: - core graphics objects – базовые графические объекты (графические примитивы), которые используются высокоуровневыми функциями рисования и составными объектами (composite objects) для создания различного вида графиков и диаграмм (см. рисунок 1.6). Графические примитивы являются потомками объекта axes (оси), который задает двумерную или трехмерную систему координат для отображаемых данных. К графическим примитивам относятся такие объекты, как image ("изображение"; используется для отображения двумерной числовой матрицы, при этом значения элементов матрицы соответствуют цвету пиксела), light ("источник света", определяет направление источника света для полигонов и поверхностей; сам объект light не виден на экране), line ("линия", соединяет задающие ее точки), patch("закрашенный полигон", может содержать грани, с различными параметрами окрашивания), rectangle ("прямоугольник", двумерный объект с задаваемыми параметрами границы, заливки и степени кривизны, позволяет рисовать окружности и эллипсы), surface ("поверхность", элемент трехмерной сетки из четырехугольников, образуемых путем отображения значения элемента двумерной матрицы в виде высоты над плоскостью рисования), text ("текст", строка символов в системе координат осей). Работа с графическими примитивами относится к категории дескрипторной ("низкоуровневой") графики MATLAB; - composite objects – "сложные" графические объекта, составленные из нескольких сгруппированных базовых объектов для создания более удобного и функционального интерфейса. 12
Рисунок 1.6 – Примеры базовых графических объектов Составные объекты образуют базис для четырех подтипов графических объектов: - plot objects (графики) – объединяют некоторые базовые графические объекты, но имеют дополнительные общие свойства для графиков. Работа с методами plot-объектов относится к "высокоуровневой" графике. При визуализации данных с использованием "высокоуровневых" функций графики и изображения либо строятся каждый раз в новом окне (с параметрами отрисовки, установленными по умолчанию), либо выводятся в имеющийся объект axes с предварительным удалением всех объектов, ранее связанных с axes и сбросом параметров объекта axes в значения по умолчанию. При отображении объекта plot MATLAB самостоятельно использует графические примитивы. Потомками объекта plot являются, например, barseries ("столбиковая диаграма"), contourgraph ("контурная диаграмма"), lineseries ("набор линий"), surfaceplot("поверхность"). Большое количество разнотипных графиков и диаграмм, реализуемых методами объекта plot, существенно упрощает задачу визуализации данных, однако при необходимости создания сложного (нетипового) графика, диаграммы и т.п. без средств низкоуровневой графики обойтись трудно; - annotation objects ("объекты-примечания") – объекты (стрелки, прямоугольники, текст), размещаемые на отдельном от остальных графических объектов уровне, и используемые, как правило, для выделения или ретуширования данных, приведенных на графиках и диаграммах; - group objects ("объекты-группы") – объекты, содержащие в себе несколько других объектов и позволяющие работать с ними (например, устанавливать их параметры или выполнять преобразования) как с одним объектом; 13
- UI objects (объекты интерфейса) – объекты, используемые при создании графического пользовательского интерфейса GUI. С формой (Figure) связаны панель инструментов (uitoolbar), меню (uimenu), контекстные меню (uicontextmenu, создается аналогично объекту uimenu, но затем "назначается" том или иному объекту интерфейса) и базовые элементы управления. К базовым элементам управления относятся объекты, "типичные" для большинства интегрированных средств разработки программ (кнопки различных видов, текстовые поля, списки и раскрывающиеся списки, полоса прокрутки, таблица). Объекты uipanel и uibuttongroup представляют собой контейнеры для хранения базовых элементов управления, графических объектов и других контейнеров. Объект ActiveX является особым объектом MATLAB и позволяет организовать взаимодействие с другими приложениями посредством COM-интерфейса.
Доступ к графическим объектам в программе на MATLAB Каждому графическому объекту при создании MATLAB присваивает уникальный числовой идентификатор (handle), Идентификатор объекта root равен 0. Для остальных объектов идентификатор – это обычно число вещественного типа. Чтение и запись свойств графических объектов осуществляется функциями set() и get().Аргументы функции должны содержать идентификатор объекта и наименование свойства, которое требуется прочитать или модифицировать например: bl_size = get(hndl_1, 'Value'); set(hndl_2, 'String', 'Кодирование завершено');
В соответствии с парадигмой событийно-ориентированного программирования каждому компоненту управления сопоставлена одна (или более) процедур (callback) обработки событий. Вызов каждой такой процедуры связан с выполнением пользователем определенного действия (нажатия кнопки, выбора пункта меню, перемещения курсора мыши над элементом управления и т.п.). Содержание callback-процедур определяет пользователь, разрабатывающий пользовательский интерфейс. Наиболее распространенными типами callback-процедур в GUIDE являются: - ButtonDownFcn – вызывается по нажатию кнопки мыши над компонентом управления, для которого установлено свойство Enable. В случае, если используется для объекта Figure, то возникает когда щелчок происходит по области окна, не занятой другими объктами; - WindowsButtonDownFcn, WindowsButtonMotionFcn – вызываются при нажатии кнопки мыши или перемещении мыши (в пределах окна); - Callback – вызывается при выполнении функционального действия компонента (нажатие кнопки, или выбор пункта меню); - CloseRequestFcn – вызывается непосредственно перед закрытием формы; - CreateFcn – вызывается при создании компонента управления но до отображения формы на экране. Шаблон, генерируемый GUIDE для данной функции, обычно реализует установку цвета отображения компонента на экране; 14
- DeleteFcn – вызывается при удалении компонента из памяти; - KeyPressFcn – вызывается когда пользователь нажимает клавишу на клавиатуре, а компонент управления находится в фокусе. Параметрами вызова callback-процедуры, как правило, являются: - hObject – идентификатор (handle) элемента управления, для которого вызвана процедура обработки; - eventdata – параметр зарезервирован; - handles – структура, содержащая идентификаторы всех графических элементов, присутствующих на оконной форме. Благодаря такому набору параметров из любой callback-процедуры некоторой формы можно получить доступ к свойствам не только "родного" объекта (через идентификатор hObject), но и к свойствам любого объекта на данной форме (через структуру handles), например: bl_size = get(hObject, 'Value') set(handles.text8, 'String', 'Кодирование завершено');
В некоторых случаях для получения идентификатора графического объекта в MATLABпрограмме можно воспользоваться следующими функциями: - findobj – выполняет поиск объекта по заданным свойствами (например, имени) и возвращает идентификатор объекта; - gcb – возвращает идентификатор окна, содержащего объект, для которого вызвана процедура обработки события; - gcbo – возвращает идентификатор объекта, для которого вызвана процедура обработки события; - gca – возвращает идентификатор текущего (активного) объекта axes. Обычно используется при работе с графикой на дескрипторном ("низком") уровне; - gco – возвращает идентификатор текущего (активного) графического объекта. Обычно используется при работе с элементами управления. Подробнее средства создания пользовательского интерфейса в MATLAB средствами GUIDE и методы работы с графическими объектами описаны в *9, 10+. Организация взаимодействия MATLAB-программы с другими приложениями через COM-интерфейс и использование объектов ActiveX рассмотрены в *11].
Основы программирования на языке MATLAB Язык программирования системы MATLAB вобрал в себя все средства, необходимые для реализации различных видов программирования: процедурного, функционального, объектноориентированного, структурного (модульного), визуально-ориентированного и т.п. [12]. MATLAB имеет черты известных языков программирования высокого уровня: BASIC, Pascal, FORTRAN [13]: - среда выполнения MATLAB представляет собой интерпретатор; - отсутствует необходимость в объявлении типов и размеров переменных; 15
- обеспечивается возможность образования новых типов вычислительных объектов (классов) на основе типов объектов, уже существующих в языке; - все переменные в MATLAB являются локальными, то есть действуют лишь в границах той программной единицы (процедуры, функции или главной, управляющей программы), где им присвоены некоторые конкретные значения. При переходе к выполнению другой программной единицы, значения переменных предыдущей программной единицы или совсем теряются (в случае, если выполненная программная единица является процедурой или функцией), или становится недосягаемыми (если выполненная программа – управляющая). Обмен данными между функциями (и командами) происходит главным образом через их входные параметры; - в языке MATLAB нет глобальных переменных, однако интерпретатор MATLAB позволяет в одном и том же сеансе работы выполнять несколько самостоятельных программ, причем все переменные, используемые в этих программах, являются общими для этих программ и образуют общее рабочее пространство (Workspace); - подавляющее большинство функций и команд языка представляют собой вполне законченные модули, оформленные в виде текстовых m-файлов, которые хранятся на диске и подключаются к программам по мере необходимости. Это позволяет более рационально организовывать сложные (громоздкие) вычисления по принципу, который напоминает оверлейные структуры.
Особенности записи программы на языке MATLAB Основные особенности записи текста программы (m-файла) на языке MATLAB [13]: - обычно каждый оператор записывается в отдельной строке текста программы. Признаком конца оператора является конец строки. Можно размещать несколько операторов в одной строке, тогда предыдущий оператор этой строки должен заканчиваться символом ' ; ' или ' , '. Можно длинный оператор записывать в несколько строк. При этом предыдущая строка оператора должна заканчиваться тремя точками " ... ". - если очередной оператор не заканчивается символом ' ; ', результат его действия при выполнении программы будет выведен в командное окно. Чтобы предотвратить вывод на экран результатов действия оператора программы, запись этого оператора в тексте программы должна заканчиваться символом ' ; '. Если выражение завершается знаком ';', то MATLAB не выводит результирующее значение на экран. Обычно формат оператора с ';' используется при работе со средой в интерактивном режим, а без ';' – при написании программы; - строка программы, начинающаяся с символа ' % ', не выполняется. Эта строка воспринимается системой MATLAB как комментарий; - строки комментария, предшествующие первому выполняемому оператору программы, т. е. такому, который не является комментарием, воспринимаются системой MATLAB как описание программы; - в программах на языке MATLAB отсутствует символ окончания текста программы; - в языке MATLAB переменные не описываются и не объявляются. Любое новое имя, появляющееся в тексте программы при ее выполнении, воспринимается системой как имя 16
матрицы. Размер этой матрицы устанавливается при предварительном вводе значений ее элементов либо определяется действиями по установлению значений ее элементов, описанными в предшествующих операторах или процедуре; - имена переменных могут содержать лишь буквы латинского алфавита или цифры и должны начинаться из буквы. Общее число символов в имени может достигать 30. В именах переменных могут использоваться как прописные, так и строчные буквы. Строчные и прописные буквы в именах различаются.
Файлы-сценарии и файлы-функции Все команды, которые вводятся в командной строке (Command Window), можно сохранить в виде единой последовательности в файле с расширением ‘m’. Такой файл называется сценарием (script-файлом) и может быть запущен на выполнение из командной строки, из другого m-файла или непосредственно из текстового редактора MATLAB. Для файлов сценариев характерны следующие особенности: - они не имеют входных и выходных аргументов; - работают с данными из рабочей области, т.е. значения переменных сохраняются не только на время выполнение сценария, но и на протяжении всего сеанса работы с MATLAB; - в процессе выполнения не компилируются; - представляют собой законченную последовательность операций, полностью аналогичную той, что используется при работе с командной строкой. Структура файла-сценария обычно имеет следующий вид: %Основной комментарий (необязательный) %Дополнительный комментарий (необязательный) Тело_файла. Содержит любые допустимые выражения MATLAB
Основной комментарий выводится при выполнении команд lookfor и . Основной и дополнительный комментарии выводятся при выполнении команды . Файл-функция (также имеет расширение 'm') является полноценным модулем с точки зрения структурного программирования, поскольку содержит входные и выходные параметры и использует аппарат локальных переменных. Структура такого модуля с одним выходным параметром выглядит следующим образом (чтобы функцию можно было вызвать, ее имя (f_name) должно совпадать с именем m-файла): function var=f_name(Cпиcoк_napaмeтpов) %Основной комментарий (необязательный) %Дополнительный комментарий (необязательный) Тело файла с любыми выражениями vаr=выражение
17
Файл-функция имеет следующие свойства: - он начинается с объявления function, после которого указывается имя переменной var – выходного параметра (для случая одного выходного параметра), имя самой функции и список ее входных параметров – все это указывается в первой строке файла; - функция возвращает свое значение и может использоваться в виде f_name (Список_параметров) в математических выражениях; - все переменные, имеющиеся в теле файла-функции, являются локальными, т. е. действуют только в пределах тела функции; - файл-функция является самостоятельным программным модулем, который общается с другими модулями через свои входные и выходные параметры; - правила вывода комментариев те же, что у файлов-сценариев; - файл-функция служит средством расширения системы MATLAB; - при обнаружении файла-функции он компилируется и затем исполняется, а созданные машинные коды хранятся в рабочей области системы MATLAB; - конструкция vаг=выражение необходима, если требуется, чтобы функция возвращала результат вычислений. Если выходных параметров больше одного, то они указываются в квадратных скобках после слова function. При этом структура модуля имеет следующий вид: function [varl,var2....]=f_name(Список_параметров) %Основной комментарий (необязательный) %Дополнительный комментарий (необязательный) Тело файла с любыми выражениями vаг1=выражение vаг2=выражение
Функция языка MATLAB с несколькими выходными параметрами схожа с процедурой традиционного языка программирования высокого уровня. Ее нельзя слепо использовать непосредственно в математических выражениях, поскольку она возвращает не единственный результат, а множество результатов — по числу выходных параметров. Если функция используется как имеющая единственный выходной параметр, но в действительности имеет ряд выходных параметров, то для возврата значения функции будет использоваться первый из них. Это зачастую ведет к ошибкам в математических вычислениях. Если функция используется в виде f_nаmе(...), то возвращается значение только первого выходного параметра — переменной varl. При необходимости функции m-файла могут разделять общую переменную. Для работы с такой переменной в каждой из функций, где она используется, переменную необходимо объявить с использованием оператора global. Файл-функция (в отличие от файла-сценария) может содержать несколько функций, однако из других модулей (или рабочего пространства) может быть вызвана только первая (главная) функция модуля. При необходимости остальные функции модуля могут быть вызваны из главной функции. Более подробная информация о файлах-функция и файлах-сценариях содержится в *13,14]. 18
Типы данных MATLAB В MATLAB определены следующие основные встроенные классы вычислительных объектов и объектов управления (см. рисунок 1.7): Массив (ARRAY) обычный или разреженный
logical
char
int8, uint8, int16, uint16, int32, uint32, int64, uint64
NUMERIC
single
cell
double
structure
классы пользователя
function handle
классы Java
Рисунок 1.7 – Классы (типы данных) MATLAB - double – числовые массивы с числами удвоенной точности (все числовые данные по умолчанию имеют тип double); - single – числовые массивы с числами одинарной точности; - int64, uint64 – массивы 64-разрядных чисел со знаком и без знаков; - int32, uint32 – массивы 32-разрядных чисел со знаком и без знаков; - int16,uint16 – массивы 16-разрядных целых чисел со знаком и без знаков; - int8, uint8 – массивы 8-разрядных целых чисел со знаками и без знаков; - char – строчные массивы с элементами-символами; - logical – логические массивы, содержащие значения 1 ("истина") или 0 ("ложь"); - struct – массивы структур с полями, которые также могут содержать массивы; - сеll – массивы ячеек; ячейки, в свою очередь, тоже могут быть массивами; - sparse – наследует свойства double, разреженные матрицы с элементами-числами удвоенной точности; - date – работа с данными, представляющими собой дату и время; - function_handle – дескрипторы функций. MATLAB – система, специально предназначенная для осуществления вычислений с векторами, матрицами и полиномами. Под вектором в MATLAB понимается одномерный массив чисел, а под матрицей – двумерный массив. При этом следует четко понимать, что вектор, векторстрока, вектор-столбец или тензор – это математические объекты, а одномерный или двумерный массив – структура данных, предназначенная для хранения этих объектов в рамках программы [15,16]. По умолчанию предполагается, что любая (!) заданная переменная является вектором или матрицей (в терминах программы – массивом). Например, отдельное заданное число (скаляр) система воспринимает как матрицу размером 1х1 (массив из одной строки и одного столбца), а вектор-строку из N элементов – как матрицу размером 1хN (одномерный массив). 19
Массив, имеющий более двух измерений, называется многомерным массивом. Многомерный массив в MATLAB обычно рассматривается как расширение двумерного массива. В случае трехмерного массива третье измерение условно называется "страницей". MATLAB позволяет преобразовывать массив, изменяя размеры и даже размерность массива (функция reshape()) при условии сохранения числа элементов в массиве неизменным, выполнять перестановку размерностей массива (функция permute()), минимизировать размерность массива, т.е. удалять размерность, по которой имеется только одно возможное значение соответствующего индекса (функция squeeze()). Переменная в MATLAB создается, когда ей присваивается значение. Ниже приведены некоторые примеры формирования и инициализации числовых переменных, значения которых хранятся в одномерных и многомерных массивах:
Оператор A=1 B = [1 2 3 4 5]
Размерность переменной, тип 1x1 double 1x5 double
C = uint8([1; 2; 3; 4; 5.4])
5x1 uint8
[1 2 3 4 5]
1x5
D = uint32([1; 2; 3; 4; 5]) E = [1 2 3 4 5]' F = [1.0 2 3.9 14 -5]'' G = [1 2; 3 4; 5 6] H = [1 2 3; 4 5 6; 7 8 9]; H(:, :, 2) = [1 0 4; 5 4 3; 2 3 4]
5x1 uint32 5x1 double 5x1 double 3x2 double 3х3х2 double
I = [B F]
1 x 10 double
J = [B; F]
2x5 double 2x2 double Ошибка
K = [1 2; ; 5 6] L = [1 2; 3; 5 6]
Комментарии Создается переменная-скаляр A (матрица размером 1х1) Вектор-строка B из 5 элементов. Значения строки массива разделяются пробелом. Квадратные скобки являются конструктором числового массива Вектор-столбец из 5 беззнаковых целых чисел. Значения различных строк разделяются знаком " ; ". Округление до целого выполняется по математическим правилам Вектор-строка из 5 элементов записывается в специальную системную переменную ans, поскольку оператор не содержит знака присваивания. Полученное значение переменной ans может использоваться в следующих операторах вычислений Вектор-столбец из 5 элементов Вектор-столбец из 5 элементов получается путем транспонирования (знак " ' ") вектора-строки Вектор-строка из 5 элементов получается путем двойного транспонирования вектора-строки Матрица из 3-х строк и 2-х столбцов. Значения различных строк разделяются знаком ";" Сначала создается двумерный массив H(3х3). Затем инициализируются значения второй страницы (добавляется третье измерение). Результат – трехмерный массив из 3-х строк, 3-х столбцов и 2 "страниц" Вектор-строка из 10 элементов. Сначала последовательно заносятся 5 элементов вектора B, затем – 5 элементов вектора F Матрица из 2-х строк и 5 столбцов. Первая строка – элементы вектора B, вторая строка – элементы вектора F Неинициализированные строки автоматически удаляются из матрицы. Данный оператор эквивалентен "А=*1 2; 5 6]" Количество значений для строк не соответствует количеству значений для столбцов 20
Оператор M = [-0.1 : 0.3 : 1.4] N = zeros(4, 6) O = ones(3, 5, 2) P = rand(10) R = 2*ones(4) S = eye(2) T = repmat(R, 2, 3)
Размерность переменной, тип 1х6 double 2x6 double 3x5x2 double 10x10 double 4x4 double 2x2 double 4x6 double
Комментарии Вектор-строка *-0.1 0.2 0.5 0.8 1.1 1.4]. Задается начальным значением, шагом, конечным значением. Матрица из 4-х строк и 6 столбцов, содержащая нулевые элементы Трехмерный массив размерностью 3х5х2 элементов, содержащий единичные элементы Матрица размером 10х10 элементов, равномерно распределенных в диапазоне от 0 до 1 Матрица размером 4x4 элемента, все значения которой равны 2 Единичная матрица S размером 2x2 элемента (единицы расположены на главной диагонали. Матрица T размером 4x6 элементов, которая получается путем дублирования матрицы S 2 раза по вертикали и 3 раза по горизонтали
Кроме числовых типов данных в MATLAB реализована поддержка символьных данных, записей (структур) и ячеек. Строка в MATLAB представляет собой одномерный массив (вектор), компоненты которого содержат числовые коды символов. Код каждого символа при хранении занимает 2 байта памяти. Один символ хранится в массиве размером 1х1, строка из N символов – в массиве размером 1xN (класс char). Массив объектов типа char может хранить несколько строк, причем все строки должны быть одинаковой длины, например: name = ['Ivanov S.P. '; ... 'Morkovkin A.V. '; ... 'Cheremushkin K.D.'];
Как видим, в случае, если строки имеют различную длину, то они должны быть дополнены пробелами до длины самой длинной строки. Избежать данных проблем помогает использование массива ячеек (Cell Array). Если обычный массив MATLAB содержит данные одного типа, то массив ячеек – это массив, элементами которого являются ячейки, которые сами могут содержать любой тип массива, в том числе и массив ячеек. Массивы ячеек позволяют хранить массивы с элементами данных разных типов. Создание массива ячеек может выполняться при инициализации содержимого ячеек (см. ниже), а может быть выполнено путем вызова функции вида: D = cell(100, 1); % создание одномерного массива ячеек из 100 элементов (ячеек)
Массивы записей (структур) – это тип массивов в системе MATLAB, в котором разрешается сосредоточивать в виде записей разнородные данные (т. е. данные разных типов (классов)). Отличительной особенностью таких массивов является наличие именованных полей. Как и 21
вообще в MATLAB, массивы записей не объявляются. Отдельные экземпляры этого класса создаются автоматически при задании конкретных значений полям записи: FIO.family = 'Ivanov'; FIO.name = 'Ivan'; FIO.surname = 'Ivanovich'; FIO.god = 1990
или путем использования оператора struct: <имя записи> = struct('<имя поля1>', <значение1>, '<имя поля2>', <значение2>, ...). Например: FIO = struct('family','Ivanov,'name','Ivan','surname','Ivanovich','god', 1990)
При создании массива записей новые записи добавляются путем указания соответствующего индекса: FIO(2).family = 'Petrov'; FIO(2).name = 'Petr'; FIO(2).surname = 'Petrovich'; FIO(2).god = 1996;
Если к какому-либо из элементов массива записей (структуры) добавляется значение нового поля, то же поле автоматически появляется во всех остальных элементах, хотя значение этого поля у других элементов при этом остается пустым. Чтобы установить, какому классу принадлежит объект, используется функция class(). Вопросы использования объектно-ориентированного программирования при обработке данных на языке MATLAB выходят за рамки данного краткого введения и детально рассмотрены в [13, 17].
Доступ к элементам массивов, ячеек и структур данных Обращение к элементам массива осуществляется путем указания индекса. Использование диапазонов значений индексов позволяет получить доступ к подмассиву исходного массива [18]. Примеры доступа к отдельным элементам описанных ниже переменных A и B, приведены в таблице: A = [1 2 3 4; 5 6 7 8; 9 10 11 12]; B = [1.1 -2.1 3.4 4.5 5.8; 6.7 7.9 8.4 9.6 10.2]; Оператор A(2,3)
Размерность результата 1x1
Комментарии В системную переменную ans заносится значение элемента массива, расположенного на пересечении второй строки и 22
Оператор
Размерность результата
C = A(1:2,3:4)
2x2
D = B(1, :)
1x5
E = [A(2:3,2:3) B]
2x7
A(:, 1) = 0 F = zeros(10); H = ones(2); F(5:6,5:6) = B
размерность матрицы A 10x10
Комментарии третьего столбца В переменную C заносится подматрица, состоящая их элементов правого верхнего угла матрицы А: [3 4; 7 8] В вектор-строку D заносятся все элементы первой строки матрицы B В матрицу E заносится подматрица матрицы A, а затем к ней слева "приписывается" матрица B Первый столбец матрицы A заполняется нулями Результатом является матрица F размером 10x10 элементов, четыре центральных элемента которой равны 1, а остальные 0.
При "переинициализации" переменной (всей переменной, а не ее части!) матрицей другого размера, размер переменной автоматически корректируется. Хранение матрицы в MATLAB осуществляется по столбцам, сверху-вниз. Поэтому к каждому элементу, например, двумерной матрицы можно получить доступ, либо два индекса (номер строки и номер столбца), либо указав номер элемента в "линейной развертке" матрицы. При доступе к элементам многомерного массива сначала указывается номер строки, затем номер столбца, затем номер "страницы" (для трехмерного массива), как показано на рисунке 1.8. Понятно, что количество индексов должно соответствовать размерности массива.
Рисунок 1.8 – Индексы элементов многомерного (трехмерного) массива в MATLAB При этом MATLAB позволяет получить доступ не только к одному элементу массиву, но и к целой строке, столбцу, странице и т.д., как это показано на рисунке 1.9. Чтобы реализовать такой режим доступа необходимо зафиксировать один или несколько из индексов (т.е. указать в них конкретные значения), а вместо остальных значений индексов указать знак ":" или необходимый диапазон значений, например, "1:3".
23
Рисунок 1.9 – Доступ к "странице" трехмерного массива в MATLAB Доступ к элементам массива ячеек (в отличие от доступа к элементам массива) обычно осуществляется путем указания индекса в фигурных скобках, например: C{1,1} C{1,2} C{2,1} C{2,2}
= = = =
'Ivanov S.P.'; [1 2 3 4 5]; [1 2 3; 4 5 6; 7 8 9]; uint8(1:1:10);
Для символьного и графического отображения массива ячеек используются функции celldisp() и cellplot(). Доступ к элементам массива записей не отличается от доступа к элементам массива структур в традиционных языках программирования и также требует указания номера записи и имени поля. Непосредственное использование в расчетах классов cell и struct затруднительно, тем не менее они используются в MATLAB для хранения информации, а также при создании новых классов объектов.
Виды операций над массивами Операции с массивами в MATLAB можно разделить на 2 группы [13]: - векторные (матричные) операции, выполняемые по правилам математики. К таким операциям относятся сложение векторов, вычитание векторов, транспонирование вектора, умножение вектора на число, умножение двух векторов (определено только когда один из векторов – строка, а другой – столбец и оба вектора имеют одинаковое количество элементов, в зависимости от порядка операндов результатом может быть либо число, либо квадратная матрица), векторное произведение (определено только трехкомпонентных векторов, вызывается как функция); - математические операции над элементами массивов. К таким операциям относятся все элементарные математические функции MATLAB от одного аргумента (например, sin(x), exp(x) и т.п., где x – матрица произвольной размерности) и некоторые стандартные математические операции (прибавление числа ко всем элементам матрицы, поэлементное умножение матриц (оператор ".*"), поэлементное деление матриц (оператор ".\"), поэлементное возведение 24
матрицы в степень (оператор ".^"), причем для операций поэлементного умножения и деления матрицы должны быть одинакового размера).
Построение простейших графиков функций MATLAB обладает мощными средствами визуализации данных. Рассмотрим кратко пример построения с использованием MATLAB функции одной переменной. Построение простейшего графика функции состоит из трех этапов: - задание вектора значений аргумента; - вычисление вектора значений функции для заданных значений аргумента; - вызов команды plot для построения графика функции. Например (см. рисунок 1.10): x = [0:0.1:1.0]; y = exp(x) .* (10*x); plot(x, y);
% формируется вектор x из (1х11) элементов % формируется вектор y из (1х11) элементов, причем yi = exi * (10*xi) % создается окно с областью рисунка, в котором выводится график функции
Рисунок 1.10 – Результат использования функции plot() для построения графика функции Если в списке аргументов функции plot() указать только один аргумент, то он будет интерпретирован как вектор значений функции для значений аргумента 0, 1, 2, ... Если в качестве аргумента значений функции указать не одномерный, а двумерный массив, то для каждого столбца (!) этого массива в области рисунка будет построен свой график. Например, для двумерного массива C = [1 2 3; 4 5 6; 7 8 9] будут построены три графика со значениями функции *1 4 7+, *2 5 8+ и *3 6 9+ и общими значениями аргумента *1 2 3+. MATLAB поддерживает более 30 способов графического представления двумерных данных и более 20 способов – трехмерных. Детально они описаны в *10].
25
Управление программой на языке MATLAB Помимо программ с линейной структурой, инструкции которых исполняются строго по порядку, существует множество программ, структура которых нелинейна. При этом ветви программ могут выполняться в зависимости от определенных условий, иногда с конечным числом повторений — циклов, иногда в виде циклов, завершаемых при выполнении заданного условия. Практически любая серьезная программа имеет нелинейную структуру. Для создания таких программ необходимы специальные управляющие структуры. К таким управляющим структурам в языке MATLAB относятся условные операторы, операторы организации цикла, оператор обработки исключений и оператор возврата из функции. Синтаксис
if logical_expression_1 statements_1 [elseif logical_expression_2 statements_2] [else statements_3] end
switch expression case value_1 statements_1 [ case value_2 statements_2] ... [ otherwise statements_n] end
for index=start:inc:end statements end
while expression statements end
Пример Комментарии Условные операторы: if A(2, 3) == 0 Проверка на эквивалентность значений B = A*C; выполняется с использованием оператора "=", на end неравенство – оператора "~=" Если оцениваемое логическое выражение if A приводит к получению нескалярного значения, то B = A*C; условие считается истинным, если все(!) end элементы аргумента не равны нулю if A(1,1) > 0 Для организации "вложенных" условных B = A*C операторов можно использовать оператор elseif elseif A(1,1) < 0 B = A*A end switch input_num В качестве оцениваемого значения expression case -10 может использовать либо скаляр, либо строка. В a = 32; отличие от языка С при попадании в одну из case {-5, 0, 5} ветвей case, управление не "проваливается" в a = 64; нижеследующие ветви – остальные casecase 10 варианты не выполняются. Поэтому оператор a = 128; break в данном случае не используется. otherwise Оператор switch может отрабатывать a = 0; множественные проверки в каждой ветви case end Операторы цикла: Выполнение итераций завершается, когда значение переменной цикла становится больше (меньше) верхней границы для положительного for i=2:1:10 (отрицательного) модификатора. Допускается a(i) = a(i-1) формат записи пределов изменения переменной end цикла в виде start:end. В этом случае MATLAB использует значение модификатора переменной, равное единице. В цикле for можно использовать операторы continue и break n = 1; В цикле while можно использовать операторы while n < 100 continue и break n = n + 1; end 26
try statements_1 catch statements_2 end
return
Оператор обработки исключений Последовательность между операторами try и catch выполняется до тех пор, пока не произойдет ошибка. В этом случае управление передается на операторы внутри блока catch. Текст сообщения о причине ошибки, идентификатор ошибки и состояние стека можно получить с использованием функции lasterror Оператор возврата из функции Оператор позволяет вернуть управление из функции в вызывающую программу до нормального завершения выполнения функции
Примеры реализации простейших алгоритмов обработки векторных и матричных данных средствами MATLAB Ниже приводятся примеры вычисления типовых математических операций над векторами и матрицами, которые лежат в основе большинства алгоритмов обработки данных [15, 16]. Скалярное произведение двух векторов одинакового размера. Скалярное произведение векторов a и b длины N, состоящих из действительных чисел, определяется как сумма попарных произведений элементов этих векторов. Для вычисления скалярного произведения можно использовать следующее выражение MATLAB: res1 = sum(a .* b) Результатом вычислений будет число res1 (массив размером 1х1). Модуль вектора. Модуль вектора равен квадратному корню из суммы квадратов всех элементов вектора. На языке MATLAB выражения для вычисления модуля вектора можно записать следующим образом: res2 = sqrt(sum(a .* a)) Результатом вычислений будет число res2 (массив размером 1х1). Векторное произведение векторов. Векторное произведение векторов a x b определено в MATLAB только для векторов из трехмерного пространства, т.е. состоящих из трех элементов. Для вычисления векторного произведения может использоваться специальная функция cross: res3 = cross(a, b) Результат res3 является вектор в трехмерном пространстве (массив 1х3 или 3х1, в зависимости от того, являлись ли исходные вектора соответственно строками или столбцами). Вычисление среднего значения вектора. Для вычисления среднего значения вектора необходимо найти сумму всех его элементов и разделить на число элементов (размер вектора). Размер массива a можно определить функцией size(a), однако следует помнить, что функция вернет вектор, содержащий количество значений, равное размерности массива (т.е. будет подсчитано число элементов для каждого измерения массива). Чтобы подсчитать число элементов для какого-то конкретного измерения массива, следует использовать формат вызова size(a, номер_измерения), которая вернет единственное число.
27
Таким образом, требуемый результат для случая, если вектора а – вектор строка, можно получить, применив выражение res4 = sum(a) / size(a, 2) Более простым способом получения желаемого является использование встроенной функции MATLAB mean(): res4 = mean(a) Результатом вычислений в обоих случаях будет число res4 (массив размером 1х1). Вычисления евклидова расстояния между двумя векторами. Евклидово расстояние между двумя векторами равно квадрату из суммы квадратов поэлементных разностей векторов. res5 = sqrt(sum( (a-b) .^ 2)) Результатом вычислений будет число res5 (массив размером 1х1). Нахождение суммы элементов матрицы. Как отмечалось выше применение функции суммирования sum() к двумерному массиву приведет к вычислению суммы независимо по каждому столбцу матрицы (т.е. формируется вектор-строка с суммами по столбцам). Чтобы получить итоговую сумму матрицы надо сложить найденные суммы: res6 = sum(sum(a)) Результатом вычислений будет число res6 (массив размером 1х1). Сортировка строк в массиве. Рассмотрим случай, когда имеется матрица, все строки которой представляют собой последовательности символов одинаковой длины, например: a = ['abcd '; 'as ', 'asdfg']. Для сортировки строк такой матрицы по возрастанию удобно использовать функцию sortrows(): res7 = sortrows(a) Результатом вычислений будет массив res7 той же размерности, что и а. Детальное описание встроенных функций MATLAB приведено в руководствах [19-21].
Способы оценки производительности и повышения эффективности программ на языке MATLAB Для анализа эффективности программы и выявления тех ее фрагментов, которые требуют оптимизации, в MATLAB используются следующие средства: 1) утилита профилирования (Profiler), которая позволяет оценить относительное время выполнения той или иной части программы, чтобы выявить наиболее проблемные фрагменты кода. Запуск профайлера можно выполнить из редактора m-файлов (пункт меню Tools→Open_Profiler) или набрав в командной строке среды (Command Window) команду profile view и введя имя функции, которую следует запустить на выполнение. По результатам профилирования (см. рисунок 1.11) оценивается время выполнения каждой функции (в том числе без учета времени выполнения вложенных функций) и ее отдельных строк, время выполнения вложенных функций, подсвечиваются наиболее "проблемные" участки кода. Подробные инструкции по использованию профайлера можно найти в *6+; 28
2) специальные функции tic и toc – позволяют путем соответственно включения и выключения таймера измерить "абсолютное" время выполнения программы или ее части для оценки эффективности алгоритма, сравнения производительности различных аппаратных платформ и т.п. Хотя для аналогичной цели может использоваться функция cputime, разработчики пакета MATLAB рекомендуют использовать именно функции tic и toc, обеспечивающих получение более достоверных оценок, особенно на многоядерных (hyperthreading) процессорах, начиная с Intel Pentium IV.
Рисунок 1.11 – Результат работы профайлера для функции Profiling1 (код модуля Profiling1.m приведен в левом верхнем окне). Справа внизу – краткая статистика, справа - подробная Повышение производительности выполнения программ на языке MATLAB может достигаться за счет использования следующих основных приемов: - использования распараллеливания вычислений. MATLAB поддерживает как "неявное" распараллеливание (multithreading, в основном достигается за счет выполнения отдельных задач в виде потоков на разных процессорных элементах (ядрах) одного компьютера при соответствующих аппаратных возможностях, повышает производительность выполнения базовых операций над матрицами, не требует внесения каких-либо изменения в программный код, включается в окне установок (Preferences) MATLAB) и "явное" (выполнение отдельных задач на различных компьютерах с использованием пакета Parallel Computing Toolbox, увеличивает производительность при больших объемах вычислений в каждой задаче, требует модификации программного кода); - векторизация циклических операций, т.е. замена цикла с несколькими итерациями, в котором выполняется обработка скалярных значений, одной операций с вектором или матрицей, например: Исходный код Код после оптимизации i = 0; t = 0 : .01 : 10; 29
for t = 0 : .01 : 10 y = sin(t); i = i + 1; y(i) = sin(t); end "Векторизированный" код в среде MATLAB будет выполняться значительно быстрее за счет реализации "накладных расходов" (организации цикла, выполнения переходов между элементами массива и т.п.) внутренними средствами MATLAB. Особенно полезными при векторизации могут быть такие функции, как all(), any(), sumsum(), find(), prod(), sort(), sum() и др.; - предварительное распределение памяти под массивы. Если в теле цикла присутствуют операции, выполнение которых приводит к динамическому увеличению размера массива, то регулярный поиск в оперативной памяти непрерывных блоков нужного размера средствами MATLAB будет существенно снижать производительность программы. Чтобы избежать этого рекомендуется до начала цикла выделить под массив память максимально необходимого размера, например: Исходный код Код после оптимизации x = 0; x = zeros(1, 1000); for k = 2:1000 for k = 2:1000 x(k) = x(k-1) + 5; x(k) = x(k-1) + 5; end end - в случае использования типа данных (класса), отличного от double, указание типа значений матрицы непосредственно при создании матрицы во избежание выполнения операции преобразования типа над большим объемом данных: Исходный код Код после оптимизации A = int8(zeros(100)); A = zeros(100, 'int8'); Дополнительные возможности и приемы повышения производительности выполнения программ на языке MATLAB рассмотрены в *14, 23]
Вопросы для самопроверки 1. Каким образом объявляются переменные в языке MATLAB? 2. В чем заключаются различия между файлом-сценарием и файлом-функцией? 3. Как можно задать матрицу или вектор с MATLAB? 4. Чем отличаются поэлементные операции от обычных операций над матрицами? 5. Как построить столбцовую диаграмму? гистрограмму? 6. В чем заключается векторизация вычислений в MATLAB и в чем преимущества векторизации? 7. Какие инструкции в языке MATLAB используются для организации циклов? 8. Что такое массив ячеек? 9. Как хранятся матрицы в MATLAB? 10. Как осуществляется взаимодействие с пользователем при использовании GUI?
30
Контрольные задания Виды заданий: 1. Найти значение арифметического выражения 2. Найти сумму элементов ряда 3. Построить матрицу с заданной структурой 4. Написать программу для вычисления выражения, содержащего повторяющееся подвыражение. Оформить процедуру вычисления подвыражения в виде файл-функции 5. Выполнить профилирование разработанной в п.4 программы 6. Разработать программу с оконным интерфейсом, которая позволяет вводить необходимое число значений, выполняет вычисление и выводит результат в числовом и/или графическом виде Вариант задания для сдачи лабораторной работы получить у преподавателя.
Список использованных источников к лабораторной работе № 1 1. http://www.answers.com/topic/the-mathworks-inc 2. The MathWorks - http://www.mathworks.com 3. http://ru.wikipedia.org/wiki/MATLAB 4. Learning MATLAB 7. – The MathWorks, 2005 5. Гультяев А. Визуальное моделирование в среде MATLAB: учебный курс. – СПб: Питер, 2000 6. MATLAB 7. Desktop Tools and Development Environment. – The MathWorks, 2008 7. MATLAB 7. Getting Started Guide. – The MathWorks, 2008 8. MATLAB 7. MAT-File Format. – The MathWorks, 2008 9. MATLAB 7. Creating Graphical User Interfaces. – The Mathworks, 2008 10. MATLAB 7. Graphics. – The Mathworks, 2008 11. MATLAB 7. External Interfaces. – The Mathworks, 2008 12. Иллюстрированный самоучитель по MATLAB. – realcoding.net 13. Лазарев Ю.Ф. Начала программирования в среде MatLAB: Учебное пособие. – К.: НТУУ "КПИ", 2003 14. MATLAB 7. Programming Fundamentals. – The Mathworks, 2008 15. Ануфриев И.Е. Самоучитель MatLab 5.3/6.x – СПб.:БХВ-Петербург, 2003 16. Ануфриев И.Е., Смирнов А.Б., Смирнова Е.Н. MATLAB 7. – СПб.: БХВ-Петербург, 2005 17. MATLAB 7. Classes and Object-Oriented Programming. – The Mathworks, 2008 18. Ануфриев И.Е. Методическое пособие "Информатика. Пакет MatLab" – Изд-во СпбГПУ, 2003. http://amd.stu.neva.ru/anufriev/MLab/mlad.htm 19. MATLAB 7. Function Reference. Volume 1: A-E. – The MathWorks, 2008 20. MATLAB 7. Function Reference. Volume 2: F-O. – The MathWorks, 2008 21. MATLAB 7. Function Reference. Volume 1: P-Z. – The MathWorks, 2008 22. MATLAB 7. Desktop Tools and Development Environment. – The Mathworks, 2008 23. MATLAB 7. Programming Tips. – The Mathworks, 2008 31
ЛАБОРАТОРНАЯ РАБОТА 2. РЕАЛИЗАЦИЯ И ИССЛЕДОВАНИЕ АЛГОРИТМА КОМПРЕССИИ ИЗОБРАЖЕНИЙ Цель лабораторной работы – реализовать средствами MATLAB алгоритм компрессии изображений и исследовать зависимость результатов кодирования от параметров алгоритма. Основные задачи: - средствами GUIDE и редактора m-файлов MATLAB разработать графический интерфейс пользователя, позволяющий в интерактивном режиме управлять параметрами кодирования и анализировать результаты кодирования (степень компрессии и качество кодирования); - разработать структуры данных для хранения исходного и результирующего изображений, промежуточных данных при кодировании и декодировании; - реализовать заданный алгоритм обработки панхроматических (в градациях серого) или цветных изображений; - провести эксперименты с целью оценки влияния на качество и степень компрессии основных параметров алгоритма кодирования.
Основные требования к выполнению работы Разработать программу на языке MATLAB, реализующую кодирование и декодирование цветного или серого изображения. Программа должна иметь разработанный средствами GUIDE пользовательский интерфейс, позволяющий: - выбирать файл для обработки; - задавать (выбирать) значения параметров алгоритма кодирования; - запускать процессы кодирования и декодирования изображения; - выводить на экран исходное и восстановленное изображения для визуальной оценки качества кодирования; - рассчитывать степень компрессии изображения; - рассчитывать оценку степени соответствия восстановленного изображения исходному (качество кодирования) – с использованием соотношения "сигнал-шум" или среднеквадратичной ошибки. Отдельные этапы обработки изображений следует реализовывать в программе в виде самостоятельных функций внутри основного модуля (или самостоятельных файлов-функций). Программный код должен быть структурирован, содержать комментарии различных уровней на русском языке. Особое внимание следует уделить использованию "ориентации" MATLAB на обработку векторных и матричных значений, избегая по возможности применения явных циклических конструкций для повышения производительности вычислений.
Общие требования к содержанию отчета по лабораторной работе 32
Отчет по работе должен содержать: 1) титульный лист; 2) формулировку задания (в соответствии с вариантом); 3) краткое описание алгоритма компрессии, включающее: - общую характеристику алгоритма (сильные и слабые стороны, возможности эффективной реализации на ЭВМ, на какие данные ориентирован и т.п.); - описание алгоритма кодирования изображения (кодера) с обязательной ссылкой на источник литературы; - описание алгоритма декодирования изображения (декодера) с обязательной ссылкой на источник литературы; - упрощения алгоритма обработки данных (отличия от описанного) и обоснования их использования; 4) описание интерфейса пользователя, вид экранной формы с элементами управления в режиме конструктора (Editor Layout) и/или в режиме выполнения; 5) список элементов управления и соответствующих им callback-процедур, которые реально используются при обработке данных ("пустые" шаблоны callback-процедур, сгенерированные GUIDE, приводить не следует), и краткое описание функционального назначения этих процедур; 6) список модулей (m-файлов) с кратким описанием их функционального назначения и связей между модулями; 7) структурная схема (схемы) алгоритма обработки данных с указанием последовательности вызовов, передаваемых данных, имен вызываемых функций; 8) перечень переменных, описанных с модификатором global; 9) описание использованных способов повышения эффективности выполнения программы за счет векторизации обработки данных и других рассмотренных приемов; 10) результаты проведенных экспериментов; 11) список использованных источников; 12) листинги всех m-модулей программы с подробными комментариями. Пример. Разработка программа кодирования изображения по алгоритму JPEG В качестве примера разработана программа, выполняющая компрессию изображений по стандарту JPEG. Описание реализации алгоритма приведено в соответствии с требованиями к отчету по работе. Разработанный интерфейс пользователя содержит дополнительные возможности, позволяющие анализировать результаты кодирования по отдельным блокам изображения (просмотр коэффициентов ДКП и коэффициентов масштабирования, просмотр результатов применения ДКП к изображению, просмотр в укрупненном виде одного блока изображения, полученных для него коэффициентов преобразования и восстановленного изображения). Реализация этих возможностей обусловлена необходимостью демонстрации на примере возможностей работы с различными элементами управления. В рамках выполнения лабораторной работ реализация таких дополнительных возможностей является необязательной.
33
Краткое описание алгоритма JPEG Общая характеристика алгоритма. Алгоритм JPEG разработан как метод сжатия непрерывнотоновых изображений. На практике он характеризуется сравнительно высоким коэффициентом сжатия, большим числом параметров кодирования, позволяющих найти баланс между степенью и качеством компрессии, возможностью использования "быстрой реализации" алгоритма прямого и обратного преобразования изображения (ДКП), возможностью использования только целочисленной арифметики при реализации. К недостаткам алгоритма могут быть отнесены дефекты, проявляющиеся в виде регулярных блоков одинакового размера на восстановленном изображении при сильной степени компрессии. Кроме того, возможно проявление эффекта Гиббса – ореолов по границам резких переходов цветов. Компрессия/декомпрессия изображения выполняется путем последовательного применения нескольких различных алгоритмов обработки данных. Рассматривается стандартный режим работы алгоритма. Краткое описание алгоритма кодирования. Основные шаги сжатия по алгоритму JPEG состоят в следующем *1+. 1) Цветное изображение преобразуется из цветового пространства RGB в цветовое пространство, состоящее из компоненты яркости (Y) и двух компонент цветности (I и Q), например: Y = 0.299R + 0.587G + 0.114B I = 0.596R – 0.274G – 0.322B Q = 0.211R – 0.522G + 0.311B На практике в JPEG используется перевод в пространство YCbCr, ориентированное на 8битовое представление компонент. Различия между цветовыми пространствами YCbCr и YIQ для данной задачи несущественно. Глаз менее чувствителен к ошибкам в передаче цветности, нежели яркости. Поэтому кодировать компоненты цветности можно с меньшей точностью, чем компоненту Y. Для этого выполняется понижение частоты дискретизации (прореживание) компонент цветности в 2 или даже 4 раза по каждой размерности. Далее каждая компонента кодируется отдельно. 2) Пикселы цветовой компоненты разбиваются на блоки NxN пикселов. Если количество пикселов не кратно N, то последняя строка и/или столбец повторяются необходимое число раз. 3) К каждому блоку применяется дискретно-косинусное преобразование
где S(x,y) – исходное значение амплитуды пиксела с координатами x и y внутри блока, D(i,j) – значение элемента (i,j) матрицы коэффициентов преобразования (0i,jN-1), а значения C(i) и C(j) рассчитывается по формуле
.
4) Каждая из 64 компонент делится на специальное число – коэффициент квантования. Обычно таблица коэффициентов квантования является статически заданной и передается вместе с
34
закодированным изображением. Один из способов формирования таблицы квантования Q является использование формулы Q(i,j) = 1 + (i+j) * R где i,j – номер строки и столбца в блоке (0i,jN-1), R – некоторый показатель качества (R = 100Quality+1). Чем больше значение R, тем сильнее квантование и, соответственно, ниже качество восстановленного изображения. 5) Квантованные коэффициенты ДКП после округления преобразуются из матричного представления в линейное таким образом, чтобы в элементы были расположены в векторе в порядке убывания значимости (с точки зрения "важности" кодируемых частот). Для этого используется зигзагообразный обход матрицы коэффициентов, проиллюстрированный на рисунке: 1
2
6
7
3
5
8
13
4
9
12
14
10
11
15
16
Обход обычно реализуется на основе рассчитываемых заранее индексов табличной перестановки. Например, для блока 4х4 такой таблицей является: (1,1) (1,2) (2,1) (3,1) (2,2) (1,3) (4,1) (2,3) (3,2) (4,1) (4,2) (3,3) (2,4) (3,4) (4,3) (4,4) 6) К полученному вектору коэффициентов применяются дополнительные методы кодирования. При этом обычно первый коэффициент (DC) кодируется в виде кода Хаффмана для разности с DC-коэффициентом предыдущего блока, а остальные (AC) коэффициенты кодируются с использованием комбинации RLE и метода Хаффмана (или арифметического кодирования). При кодировании DC коэффициента сначала унарным кодом кодируется длина бинарного представления DC-коэффициента, а затем записывается собственно значение коэффициента. В последовательности AC-коэффициентов, как правило, значительная часть нулевых значений. Для кодирования каждого ненулевого значения x кодер а) определяет число предшествующих ему нулей (Z), б) определяет длину унарного кода (R) числа x и номер числа x среди всех чисел с данной длиной двоичного представления (C), в) заменяет пару на код переменной длины Хаффмана (H), выбираемый из заранее заданной статической таблицы с монотонно возрастающими длинами кодов, г) приписывает H к C (C представлено в виде R битов) и выдает полученное кодовое слово в битовый поток. После кодирования последнего ненулевого коэффициента в выходной поток записывается специальный четырехбитовый код окончания блока (EOB), отсутствующий в таблице кодов Хаффмана. 7) Полученный битовый поток дополняется заголовком, содержащим параметры изображения, таблицы квантования, таблицу Хаффмана и записывается в файл или передается в канал связи. Краткое описание алгоритма декодирования. Основные шаги декодирования по алгоритму JPEG состоят в следующем *1+.
35
1) Из файла (канала связи) читается битовый поток, из которого выбирается заголовок, таблицы квантования и таблица Хаффмана, а также параметры (размеры) изображения. Рассчитывается количество блоков по вертикали и горизонтали. 2) Последовательно выполняется декодирование DC и AC коэффициентов каждого блока и формирование вектора коэффициентов ДКП. 3) Выполняется формирование матрицы коэффициентов ДКП-преобразования каждого блока путем применения такой же таблицы для обхода, как и при кодировании (только в обратном направлении). 4) Выполняется обратное масштабирование (квантование) коэффициентов ДКП каждого блока путем поэлементного умножения значений блока на соответствующие значения матрицы коэффициентов квантования Q. 5) К каждому блоку применяется обратное ДКП-преобразование:
где S(x,y) – исходное значение амплитуды пиксела с координатами x и y внутри блока, D(i,j) – значение элемента (i,j) матрицы коэффициентов преобразования (0i,jN-1), а значения C(i) и C(j) рассчитывается по формуле
.
6) Выполняется обратное изменение (повышение) частоты дискретизации компонент цветности. 7) Выполняется переход из пространства YCbCr в пространство RGB R = 1.0*Y + 0.956*I + 0.621*Q G = 1.0*Y – 0.272*I – 0.647*Q B = 1.0*Y - 1.106*I + 1.703*Q Упрощения и ограничения алгоритма обработки изображения, допущенные при программной реализации. При реализации с целью сокращения трудоемкости разработки использованы следующие допустимые упрощения и ограничения стандартного алгоритма: 1) программа обрабатывает только изображения в градациях серого (т.е. одна цветовая плоскость), хранящиеся в файле формата BMP. При поступлении на вход программы цветного изображения, выполняется его перевод в одноцветное "серое" изображение путем применения к каждому пикселу формулы: Y = 0.299R + 0.587G + 0.114R Поддержка только формата BMP объясняется возможностью перекодирования изображения из другого формата в формат BMP средствами практически любого графического редактора; 1) не реализован этап эффективного кодирования коэффициентов ДКП с использованием неравномерного кода Хаффмана (или арифметического кодирования). Это объясняется тем, что несмотря на наличие в MATLAB (в пакете Communications Toolbox) специализированных функций для построения дерева Хаффмана и кодирования/декодирования по Хаффману huffmandict(), huffmanenco(), huffmandeco() и аналогичных функций для арифметического кодирования, реализовать на их основе используемый в JPEG вариант неравномерного кодирования 36
коэффициентов ДКП достаточно проблематично, поскольку в JPEG используется статически заданная двумерная таблица, ставящая кодовое слово в зависимость от двух параметров. По этой же причине не выполняется сохранение компрессированного изображения в файл; 2) для оценки размера выходного битового потока на один блок изображения используется условная таблица длин кодов Хаффмана, сходная с реальной таблицей стандарта JPEG (увеличение длин кодов происходит монотонно от левого верхнего к правому нижнему углу таблицы). Поэтому, несмотря на отсутствие процедур формирования реального битового потока, оценка размера выходного битового потока для каждого блока изображения является достоверной. Кроме того, при оценки степени компрессии не учитываются заголовки как исходного изображения, так и закодированного потока. 3) размеры изображения должны быть кратны размеры выбранного блока ДКП. Для универсальности рекомендуется, чтобы размер изображения по каждой стороне был кратен 64 (максимальный поддерживаемый размер блока ДКП равен 64). В случае невыполнения этого требования кодирование не выполняется. Это связано с необходимостью дополнительной обработки блоков, имеющих неполное количество пикселов, перед выполнением прямого ДКП и после выполнения обратного ДКП. По той же причине размер изображения не может быть менее 4х4 пикселов (минимальный поддерживаемый размер блока ДКП). Необходимый размер изображения может быть получен путем использования практически любого графического редактора; 4) дополнительно к кодированию всех ненулевых коэффициентов (как предусмотрено в алгоритме JPEG) в программе добавлена возможность кодирования фиксированного числа ДКПкоэффициентов блока.
Описание интерфейса пользователя Главная экранная форма в режиме макета приведена на рисунке 2.1, а в режиме выполнения – на рисунке 2.2. При запуске программы на выполнение из редактора, оболочки GUIDE или из командной строки, на экран выводится форма, приведенная на рисунке 2.2. Она позволяет пользователю: - выбрать и загрузить BMP-файл для обработки (кнопка "Выбрать изображение"); - установить параметры алгоритма кодирования на панели "Параметры кодирования" (размер блока от 4х4 до 64х64, способ кодирования ДКП-коэффициентов блока, среднестатистическое число битов на один ДКП коэффициент (для оценки степени компрессии изображения), качество кодирования – от минимального (R=100, правый край ползунка) до максимального (R=1, левый край ползунка); - рассчитать и визуализировать форму базисных ДКП-поверхностей, накладываемых на блок изображения (для i,j от 0 до N-1) для выбранного размера блока. При этом базисные ДКПизображения появляются в новом окне, как показано на рисунке 2.3;
37
Рисунок 2.1 – Главная экранная форма программы в режиме макета
Рисунок 2.2 – Главная экранная форма программы в режиме выполнения - выполнить кодирование и декодирование изображения (кнопка "Выполнить кодирование"). После выполнения кодирования будет выведено восстановленное изображение, а также будет рассчитан коэффициент компрессии изображения;
38
Рисунок 2.3 – Базисные ДКП-изображения для блока 8х8 - рассчитать и вывести в новом окне масштабирующие коэффициенты для выбранного размера блока и заданного значения R, как показано на рисунке 2.4;
Рисунок 2.4 – Коэффициенты квантования для блока 8х8 - вывести в отдельном окне исходное изображение и восстановление изображение (кнопки с надписями "Показать в отдельном окне" соответственно под исходным изображением слева и под восстановленным изображением справа); - показать детальную информацию о кодировании одного блока изображения. Для выбора блока необходимо щелкнуть в интересующей области исходного изображения. Блок, в который попали координаты указателя мыши, будет детально проанализирован на панели "Обработка блока ДКП". При этом будут показаны изображение блока (в укрупненном масштабе), таблица коэффициентов ДКП (в таблице слева), таблица коэффициентов ДКП после квантования, 39
кодирования/декодирования и деквантования (в таблице справа), а также изображение восстановленного блока изображения (в укрупненном масштабе). Программа не выполняет проверку признака загруженности изображения и завершения кодирования, поэтому попытки вывести в отдельном окне исходное или декодированное изображение, а также выбрать область на изображении для детального анализа могут привести к генерации ошибочного сообщения в Command Window среды MATLAB.
Основные элементы управления и связанные с ними callback-процедуры Основные элементы управления, для которых выполнена разработка процедур обработки событий, приведены в таблице 2.1. Таблица 2.1 – Основные элементы управления и связанные с ними callback-процедуры Наименование элемента
Тип
pushbutton_LoadImage
кнопка
pushbutton_ShowDCTCoefs
кнопка
pushbutton_ShowQuantCoefs
кнопка
pushbutton_RunCoding
кнопка
figure1
окно
slider_Quality
слайдер
pushbutton5
кнопка
pushbutton6
кнопка
Callback-функция
Вызов по событию
Описание процедуры обработки
Загрузка bmp-изображения из файла. Если изображение нажатие pushbutton_LoadImage_Callback(...) цветное, то преобразование к кнопки серому. Результат обработки – двумерный массив Чтение параметров с формы. нажатие pushbutton_ShowDCTCoefs_Callback(...) Формирование базисных функций кнопки ДКП и вывод их в новом окне Чтение параметров с формы. нажатие Формирование коэффициентов pushbutton_ShowQuantCoefs_Callback(...) кнопки квантования и вывод их в новом окне Чтение параметров с формы. нажатие Кодирование и декодирование pushbutton_RunCoding_Callback(...) кнопки изображения. Расчет степени компрессии нажатие Если указатель мыши находится кнопки над над исходным изображением – то figure1_WindowButtonDownFcn(...) окном вне рассчитать номер блока и элементов показать детальную информацию управления по его кодированию Считывание позиции бегунка и сдвиг вывод числового значения slider_Quality_Callback(...) бегунка параметра качества в текстовое поле нажатие Вывод исходного изображения в pushbutton5_Callback(...) кнопки отдельном окне нажатие Вывод декодированного pushbutton6_Callback(...) кнопки изображения в отдельном окне
Список m-файлов (модулей) Перечень m-файлов, используемых программой, приведен на рисунке 2.5. Все файлы являются файл-функциями и вызываются из функций главного модуля – JPEG_Analysis.
40
Рисунок 2.5 – Модульная структура программы Функциональное назначение модулей function varargout = JPEG_Analysis(varargin) – шаблон файл-функции генерируется автоматически средстами GUIDE при сохранении экранной формы. Содержит callback-процедуры для некоторых элементов управления, размещенных на форме, а также функции для обработки данных. При вызове функции JPEG_Analysis создается новая экранная форма или, если форма с таким именем уже открыта, она становится активной. Вызов функции с параметрами и возврат значений не предполагается; function [coefs_scale] = Generate_Scales(N, Quality) – файл-функция, генерирует коэффициенты (масштабирующие множители) для квантования коэффициентов ДКП. Входные параметры – размер матрицы (матрица полагается квадратной), и условное значение параметра качества, выходной параметр – двумерный квадратный массив NxN коэффициентов квантования (типа double). Одна и та же матрица применяется и при кодировании, и при декодировании; function [Indices] = Generate_Zigzag(N) – файл-функция, генерирует индексы для обхода матрицы заданного размера "зигзагом". Входной параметр – размер матрицы (матрица полагается квадратной), выходной параметр – массив (размером N*N х 2) индексов элементов исходной матрицы в требуемом порядке, первый столбец соответствует номерам строк, второй – номерам столбцов элементов исходной матрицы. Одна и та же таблица индексов применяется и при кодировании, и при декодировании; function [out_linear] = UnrollMatrix(in_matrix, ind) – файл-функция, реализующая обход матрицы в заданном порядке. Входные параметры – матрица значений и массив индексов порядка обхода. Выходной параметр – вектор, содержащий значения матрицы в порядке обхода; function [out_matrix] = RollMatrix(in_linear, ind) – файл-функция, реализующая преобразование вектора в матрицу с учетом требуемого порядка расположения элементов. Входные параметры – вектор значений и массив индексов порядка обхода. Выходной параметр – матрица, содержащая значения вектора в заданном порядке; function [res] = SNR(im_x, im_y) – файл-функция, рассчитывающая отношение сигнал-шум кодирования. Входные параметры – матрицы исходного и восстановленного изображения. Выходной параметр – значения отношения сигнал-шум в децибелах. 41
function [block_bitrate] = EstimateBlockBitRate(linear_block, prev_DC, table_len) – файлфункция, рассчитывающая размер выходного битового потока для блока квантованных коэффициентов. Входные параметры – вектор квантованных коэффициентов ДКП, значение DCкоэффициента предыдущего блока, таблица кодов Хаффмана. Выходной параметр – размер выходного потока в битах.
Структурная схема алгоритмов обработки данных Структурная схема алгоритма обработки изображения приведена на рисунке 2.6. figure1 (JPEG_Analysis) нажатие на кнопку pushbutton_LoadImage щелчок мышью над окном figure1 нажатие на кнопку pushbutton_RunCoding
BMP-файл pushbutton_RunCoding_Callback()
figure1_WindowButtonDownFcn()
pushbutton_LoadImage_Callback()
Прочитать параметры кодирования с формы function read_params()
Проверить на попадание в axes_SrcImage
Загрузить изображение
Проверить размеры изображения на кратность размеру блока T = Params.NumBlock(1)*Params.NumBlocks(2)
Вычислить номера блоков по вертикали и горизонтали num_block [2,1]
Выполнить прямое ДКП function Im2DCT(SrcImage)
Вывести на форму блоки SrcImage(num_block) и DstImage(num_block)
double DCTImage [N,N]) Проквантовать коэффициенты ДКП function DCT2Scale(DCT_Image)
КОДЕР
double ScaleImage [N,N] Преобразовать в вектор function Scale2Zigzag(Scale_Image)
Заполнить таблицы блокам DCT_Image(num_block) и DeScaleDC_Image(num_block)
double CutCoefs [T,Params.BlockSize^2] Вычислить размер сжатого изображ. function EstimateBitRate(CutCoefs)
Рассчитать коэффициент компрессии
Преобразовать в серое
Преобразовать в double
Вывести на форму
struct Params double DstImage [NxN] double DCT_Image [NxN] double DeScaleDCT_Image [NxN]
double SrcImage [NxN]
Workspace (global)
double LinearCoefs [T,Params.BlockSize^2] Отбросить "лишние" коэффициенты function CutCoefs(LinearCoefs)
Изображение (NxN) или (NxNx3)
struct Params double DstImage [NxN] double DCT_Image [NxN] double DeScaleDCT_Image [NxN]
double SrcImage[NxN] double DstImage[NxN] double DCT_Image[NxN] double DeScaleDCT_Image[NxN] struct Params: ImageSize[2x2] BlockSize[1x1] NumBlocks[2x2] Quality[1x1] ...
double SrcImage [NxN]
Преобразовать в матрицу function Zigzag2Scale(CutCoefs)
ДЕКОДЕР
double DeScale_Image [N,N] Деквантование коэффициентов ДКП function Scale2DCT(DeScale_Image) double DeScaleDCT_Image [N,N] Выполнить обратное ДКП function Scale2DCT(DeScaleDCT_Image) double DstImage [N,N] Рассчитать сигнал-шум function SNR(SrcImage, DstImage)
Вывести на форму
Курсивом отмечены действия, выполняемые с использованием стандартных функций MATLAB. Пунктирные линии – вызовы процедур Штрих-пунктирные линии – передача данных Сплошные линии – передача управления
Рисунок 2.6 – Структурная схема алгоритма обработки изображения
42
Перечень переменных, описанных с модификатором global В различных функциях программы с модификатором global описаны следующие переменные: - Params – структура данных, содержащая характеристики изображения и параметры кодирования, необходимые для использования в различных функциях модуля. Состоит из следующих полей: ImageSize [1,2] – размер изображения в пикселах; BlockSize [1,1] – размер ДКП-блока; Quality [1,1] – параметр, задающий качество кодирования (степень квантования); NumBlocks [1,2] – количество блоков по горизонтали и вертикали; CompressionRatio [1,1] – рассчитанный коэффициент компрессии изображения; SN_Ratio[1,1] – отношение сигнал-шум; CodeNonZero [1,1] – флаг кодирования всех ненулевых коэффициентов ДКП; NumFirstDCTCoefs [1,1] – количество первых кодируемых коэффициентов ДКП (учитывается только при CodeNonZero = 0). - SrcImage, DstImage – двумерные массивы, содержащие исходное и восстановленное изображения соответственно. Описаны как глобальные для использования в callback-процедурах, вызываемых по различным событиям; - DCT_Image, DeScaleDCT_Image – двумерные массивы, содержащие коэффициенты ДКП исходного изображения и восстановленные после квантования/деквантования коэффициенты ДКП. Описаны как глобальные для использования в callback-процедурах, вызываемых по различным событиям.
Использованные способы повышения эффективности выполнения программы Основными использованными приемами повышения производительности в разработанной программе являются: - вынос за цикл операций, выполнение которых может привести к увеличению размера массива. В большинстве функций, выполняющих формирование массива, массив формируется путем выделения памяти командой вида ARRAY = zeros(NxM); - использование стандартных функций MATLAB для выполнения прямого и обратного дискретного преобразований (dct2, idct2), формирования списка ненулевых коэффициентов блока изображения (find), расчета отношения сигнал-шум (sum); - использование матричных операций при обработке целиком блоков данных NxN при выполнении прямого и обратного ДКП, квантования и деквантования ДКП-коэффициентов, при обнулении "неиспользуемых" коэффициентов ДКП.
43
Результаты экспериментов Для проведения исследования алгоритма кодирования проанализируем влияния на степень компрессии и качество кодирования двух параметров: - размера блока ДКП (варианты значений: 4х4, 8х8, 16х16, 32х32, 64х64 при всех кодируемых коэффициентах ДКП) – эксперимент № 1; - количество кодируемых первых коэффициентов ДКП (варианты значений: 4, 8, 16, 32, 64 при размере блока ДКП, равном 8) – эксперимент № 2. Эксперименты проводятся при постоянном значении параметра качества Quality=95. При проведении экспериментов использовались 2 изображения. Результаты экспериментов приведены в таблице 2.2. Таблица 2.2 – Результаты исследования программы компрессии изображений Изображение 1 (128х128) Изображение 2 (1024х768) Значение варьируемого Коэффициент Коэффициент С/Ш, дБ С/Ш, дБ параметра компрессии, раз компрессии, раз Эксперимент № 1 4х4 (16 коэф.) 8,2 25,7 13,1 32,1 8х8 (64 коэф.) 15,6 22,7 34,9 30,6 16х16 (256 коэф.) 26,7 19,4 73,7 28,4 32х32 (1024 коэф.) 45,1 17,2 133,7 26,2 64х64 (4096 коэф.) 78,3 15,5 232,6 24,1 Эксперимент № 2 4 32,4 14,8 46,7 23,7 8 25,3 16,2 38,4 27,4 16 19,3 19,0 35,5 29,7 32 16,8 21,1 35,0 30,1 64 15,6 22,7 34,9 30,6 В эксперименте № 1 степень компрессии увеличивается с размером блока (особенно для второго изображения), поскольку после квантования начинают преобладать нулевые коэффициенты ДКП. С увеличением размера блока качество кодирования снижается, что объясняется ухудшением адаптации алгоритма к локальным характеристикам изображения при расширении блока. В эксперименте № 2 изменение числа кодируемых ДКП-коэффициентов также приводит к изменению как степени компрессии, так и качества кодирования. Наблюдается постоянное снижения величины коэффициента компрессии, обратно пропорциональное числу кодируемых коэффициентов ДКП. График изменения отношения сигнал-шум показывает, что при кодировании более половины коэффициентов блока качество кодирования и степень компрессии изменяются слабо. Это объясняется тем, что после квантования большая часть высокочастотных коэффициентов ДКП, расположенных в правой нижней части блока, и так равна нулю.
44
Список использованных источников 1. Сэломон Д. Сжатие данных, изображений и звука. – Москва: Техносфера, 2004 2. Ватолин Д., Ратушняк А., Смирнов М., Юкин В. Методы сжатия данных. – Москва: ДиалогМИФИ. - http://compression.graphicon.ru/ 3. Рудаков П.И., Сафонов И.В. Обработка сигналов и изображений. MATLAB 5.x /Под общ. ред. к.т.н. В.Г.Потемкина. – М.: ДИАЛОГ-МИФИ, 2000 4. MATLAB 7. Mathematics. – The MathWorks, 2008 5. MATLAB 7. Data Analysis. – The MathWorks, 2008 5. Ohad Gal. JPEG Compression – www.mathworks.com (MATLAB File Exchange)
Листинг программы Модуль Generate_Scales.m function [coefs_scale] = Generate_Scales(N, Quality) % Генерация коэффициентов квантования для масштабирования коэф. ДКП % Входные параметры: % N - количество элементов в квадратной матрице % Quality - условное значение параметра качества >0 % Выходные параметры: % coefs_scale - матрица коэффициентов квантования размером NxN (double) % Алгоритм: % Формирование матрицы с монотонно увеличивающимися коэффициентами %-------------------------------------------------------------------------coefs_scale = zeros(N); % заранее генерируем квадратную матрицу %--------------------------------------------------------% Вариант 1 - с поэлементной обработкой %for m=1:N % for n=1:N % coefs_scale(m,n) = 1 + (m+n)*Quality; % end %end %--------------------------------------------------------% Вариант 2 - ориентированный на векторную обработку % выполняется быстрее в 3-5 раз (в зависимости от N) coefs_scale(1,:) = (1+(1+1)*Quality):Quality:(1+(1+N)*Quality); % генерируем первую строку for m=2:N coefs_scale(m,:) = coefs_scale(m-1,:) + Quality; % ост. строки увеличиваем на Quality end %--------------------------------------------------------------------------
Модуль UnrollMatrix.m function [out_linear] = UnrollMatrix(in_matrix, ind, ind_l) % Разворачивание матрицы в вектор путем обхода в заданном порядке % Входные параметры: % in_matrix - исходная матрица % ind - массив индексов (NxN,2) % ind_l - массив индексов (NxN,1)- индексы представлены % в виде смещений от начала массива (т.е. одним % числом)
45
% Выходные параметры: % out_linear - вектор, содержащий элементы матрицы, % упорядоченные в соответствии таблицей индексов %-------------------------------------------------------------------------n = size(in_matrix, 1); % взять размер полученной квадратной матрицы out_linear = zeros(1, n*n); % заранее выделяем место под массив-вектор 1xN^2 %--------------------------------------------------------% Вариант 1 - с поэлементной обработкой % в цикле формируем вектор, выбирая в него элементы матрицы % в порядке, который определен таблице индексов ind %for i=1:n*n % out_linear(i) = in_matrix(ind(i,1), ind(i,2)); %end %--------------------------------------------------------% Вариант 2 - с векторной обработкой % для чтения сразу нескольких элементов матрицы необходимо, чтобы % индексы ее элементов были перечислены в необходимом порядке % виде скалярных значений. out_linear = in_matrix(ind_l);
Модуль RollMatrix.m function [out_matrix] = RollMatrix(in_linear, ind, ind_l) % Сворачивание вектора в квадратную матрицу в вектор путем обхода по зигзагу % Входные параметры: % in_linear - исходный вектор % ind - массив индексов (NxN,2) % ind_l - массив индексов (NxN,1)- индексы представлены % в виде смещений от начала массива (т.е. одним % числом) % Выходные параметры: % out_matrix - матрица, содержащая элементы вектора, % упорядоченные в соответствии с таблицей индексов %-------------------------------------------------------------------------n = sqrt(size(in_linear, 2)); out_matrix = zeros(n);
% из размера вектора определить размер матрицы % заранее выделяем место под квадратную матрицу
%--------------------------------------------------------% Вариант 1 - с поэлементной обработкой %for i=1:n*n % out_matrix(ind(i,1), ind(i,2)) = in_linear(i); %end %--------------------------------------------------------% Вариант 2 - с векторной обработкой % для чтения сразу нескольких элементов матрицы необходимо, чтобы % индексы ее элементов были перечислены в необходимом порядке % виде скалярных значений. out_matrix(ind_l) = in_linear; %--------------------------------------------------------------------------
Модуль SNR.m function [res] = SNR(im_x, im_y) % Вычисление отношения сигнал-шум % Входные параметры:
46
% im_x - исходное изображение % im_y - восстановленное изображение % Изображения должны быть одинакового размера % Выходные параметры: % res - отношение сигнал-шум %-------------------------------------------------------------------------N = size(im_x,1) * size(im_x,2);
% количество пикселов в изображении
% находим мощность исходного изображения imx_sq = im_x .* im_x; % Src*Src – каждый элемент – в квадрат P_x = sum(sum(imx_sq))/N; % Power(Src) – разделить сумму всех элементов % матрицы на число элементов % находим ошибку кодирования e = im_x-im_y; % одной командой – сразу всю матрицу обрабатываем % расчет мощности ошибки e_sq = e.*e; P_e = sum(sum(e_sq))/N; % отношение сигнал-шум res = 10*log10(P_x/P_e); % присваиваем значение выходному параметру %--------------------------------------------------------------------------
Модуль Generate_Zigzag.m function [Indices, , Indices_l] = Generate_Zigzag(N) % Генерация индексов для обхода матрицы по зигзагу % Входные параметры: % N - количество элементов в квадратной матрице % Выходные параметры: % Indices - массив (N^2,2), содержащий номера строк % и столбцов элементов квадратной матрица в порядке % обхода. Первый столбец соответствует номеру строки, % второй столбец - номера столбца % Indices_l - массив (N^2,1), содержащий ту же самую % информацию, что и Indices, но номера элементов % приведены в виде одномерного смещения от начала % массива. При этом учитывается, что матрица в MATLAB % хранится по столбцам! %-------------------------------------------------------------------------Indices = zeros(N*N, 2); % заранее выделяем место под матрицу (N^2 x 2) % Первую диагонально проходим вручную (один элемент) Indices(1, :) = [1 1]; a = 2; % сдвигаем индекс в таблице индексов % обрабатываем диагонали длиной больше 1 (все, кроме первой и последней) for t=2:1:(2*N-2) % В матрице NxN строк есть 2N-1 диагоналей. Одну уже прошли % сначала отрабатываем переход на первый элемент диагонали % и устаналиваем необходимые параметры движения по ней if (rem(t,2)~=0) % если диагональ нечетная (rem – остаток от деления) dr = 1; dc = -1; % приращения для перехода к следующему элементу диагонали if (t <= N) % длина диагонали растет или уменьшается? P = t; % если растет - то число элементов равно номеру диагонали Indices(a, 1) = Indices(a-1, 1); Indices(a, 2) = Indices(a-1, 2)+1; else P = 2*N-t; % иначе: (2N - номер диагонали) Indices(a, 1) = Indices(a-1, 1)+1;
47
Indices(a, 2) = Indices(a-1, 2); end else % если диагональ четная dr = -1; dc = 1; if (t <= N) % длина диагонали растет или уменьшается? P = t; % если растет - то число элементов равно номеру диагонали Indices(a, 1) = Indices(a-1, 1) + 1; Indices(a, 2) = Indices(a-1, 2); else P = 2*N-t; % иначе: (2N - номер диагонали) Indices(a, 1) = Indices(a-1, 1); Indices(a, 2) = Indices(a-1, 2)+1; end end a = a + 1; % первый элемент диагонали обработали % теперь проходим по оставшимся элементам диагонали for i=2:1:P Indices(a, 1) = Indices(a-1, 1) + dr; Indices(a, 2) = Indices(a-1, 2) + dc; a = a + 1; end end % Последнюю диагонально проходим вручную (один элемент) Indices(N*N, :) = [N N]; % Дополнительно расчитывает линейные индексы элементов % Для преобразования (row,col) => ind может использоваться % функция sub2ind вида % ix = sub2ind([n n], ind(:,1), ind(:,2)); % Но поскольку она очень "медленная", то вместо нее % лучше рассчитывать смещение от начала матрицы "вручную". При этом % следует помнить, что в MATLAB двумерный массив хранится по столбцам. Indices_l = (Indices(:,2)-1)*N + Indices(:,1); %--------------------------------------------------------------------------
Модуль EstimateBlockBitRate.m function [block_bitrate] = EstimateBlockBitRate(linear_block, prev_DC, table_len) % Оценка размера блока в битах в соответствии с кодированием квантованных % коэффициентов ДКП в алгоритме JPEG % Входные параметры: % linear_block - массив целочисленных значений Nx1 % prev_DC - значение первого коэффициента предыдущего % блока % table_len - условная таблица длин кодов Хаффмана % (Nxn) элементов % Выходные параметры: % block_bitrate - размер блока в битах % Алгоритм: % Кодирование первого значения (DC) и остальных значений (AC) % выполняется по отдельности. % Для кодирования DC вычисляется разность между DC и prev_DC, % которая кодируется унарным кодом + само число. Для оценки % длины кода достаточно использовать двойную длину унарного % кода % При кодировании AC каждое число заменяется на пару % <число_нулей, значение>. Для этой пары берется код из % таблицы Хаффмана. Для оценки кода достаточно знать длину % этого кода
48
%-------------------------------------------------------------------------N = size(linear_block, 1); % определяем размер массива % рассчитываем размер кода для DC-коэффициента diff = linear_block(1) - prev_DC; block_bitrate = 2*(size(abs(diff),2)+1); % унарный код + само число. % рассчитываем размер кода для всех AC-коэффициентов nz_ind = find(linear_block); % получаем список всех ненулевых коэффициентов snd = size(nz_ind,2); % число ненулевых коэффициентов %--------------------------------------------------------% Вариант 1 - с поэлементной обработкой % начинаем обход всех ненулевых со второго ненулевого элемента i=2:snd Z = nz_ind(i) - nz_ind(i-1); % число нулей между ними + 1 (для доступа к таблице) x = linear_block(nz_ind(i)); % само значение R = ceil(log2(abs(x))) + 1; % длина унарного кода значения - № строки в таблице C = R; % длина номера столбца в таблице % лишняя (можно вместо C использовать R) block_bitrate = block_bitrate + table_len(R,Z+1) + C;
%for % % % % % % %end
% добавляем 4 бита на символ конца блока %block_bitrate = block_bitrate + 4; %--------------------------------------------------------% Вариант 2 - с векторной обработкой % сначала находим смещение каждого ненулевого коэффициента от % предыдущего. Для этого просто сдвигаем вектор индексов на 1 и поэлементно % вычитаем из исходного nz_ind_shift = nz_ind(1:(snd-1)); % берем только первые SND-1 ненулевых коэффициентов Z = nz_ind(2:snd) - nz_ind_shift; % вычитаем их из первого (кроме первого эл-нта) вектора x = linear_block(nz_ind(2:size(nz_ind,2))); % берем вектор самих значений R = ceil(log2(abs(x))) + 1; % рассчитываем количество битов C = R; % запомнить (лишняя, можно вместо C исп-ть R ind = (Z-1)*N+R; % находим линейные индексы для таблицы block_bitrate = sum(table_len(ind) + C) + 4; % суммируем длины кодовых слов и C + 4 бита (EOB) %--------------------------------------------------------------------------
Главный модуль JPEG_Analysis.m
function varargout = JPEG_Analysis(varargin) % Инициализационный блок, сгенерированный GUIDE gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @JPEG_Analysis_OpeningFcn, ... 'gui_OutputFcn', @JPEG_Analysis_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
49
else gui_mainfcn(gui_State, varargin{:}); end % Окончание инициализационного блока %-----------------------------------------------------------------------
%----------------------------------------------------------------------% --- Выполняется непосредственно перед визуализацией формы % --- Сгенерирован GUIDE %----------------------------------------------------------------------function JPEG_Analysis_OpeningFcn(hObject, eventdata, handles, varargin) % Choose default command line output for JPEG_Analysis handles.output = hObject; % Update handles structure guidata(hObject, handles); % UIWAIT makes JPEG_Analysis wait for user response (see UIRESUME) % uiwait(handles.figure1); %-----------------------------------------------------------------------
%----------------------------------------------------------------------% --- Выполняется непосредственно перед возвратом управления из функции % --- Сгенерирован GUIDE %----------------------------------------------------------------------function varargout = JPEG_Analysis_OutputFcn(hObject, eventdata, handles) % Get default command line output from handles structure varargout{1} = handles.output; %-----------------------------------------------------------------------
%----------------------------------------------------------------% --- Обработка нажатия на кнопку "Выбрать изображение" %----------------------------------------------------------------function pushbutton_LoadImage_Callback(hObject, eventdata, handles) global SrcImage global Params % Вызов стандартного диалогового окна для выбора файла. % Назначаем фильтр "*.bmp". % Возвращаемые параметры - имя файла и путь к файлу [fname, pname] = uigetfile( {'*.bmp', 'bmp-файл'}, ... % фильтр и его отображение 'Выберите файл изображения'); % заголовок диалога if fname~=0 % если файл выбран si = imread(fname, 'BMP'); % загрузить из файла и преобразовать в double % проверить, что изображение содержит только одну компоненту if ndims(si)>2 % если цветное - то преобразовать в серое SrcImage = double(rgb2gray(si)); else SrcImage = double(si); end % показать исходное изображение axes(handles.axes_SrcImage); % активируем нужный элемент управления imshow(SrcImage, [0 255]); % выводим в него изображение end %------------------------------------------------------------------
%------------------------------------------------------------------
50
% --- Считывание с формы параметров кодирования % --- Не является callback-функцией %-----------------------------------------------------------------function read_params(hObject, eventdata, handles) global Params % взять выбранный размер блока % прочитать в выпадающем списке (popupmenu) выбранную строку вида "99 x 99" % до первого пробела и преобразовать подстроку в число sfd = get(handles.popupmenu_BlockSize, 'String'); Params.BlockSize = str2num(strtok(sfd{get(handles.popupmenu_BlockSize, 'Value')})); % прочитать параметр качества кодирования Params.Quality = round(get(handles.slider_Quality, 'Value')); % режим кодирования коэффициентов ДКП Params.CodeNonZero = get(handles.radiobutton_CodeNonZero, 'Value'); % количество оставляемых ДКП коэффициентов Params.NumFirstDCTCoefs = 0; if (Params.CodeNonZero == 0) % если надо кодировать только первые коэффициенты Params.NumFirstDCTCoefs = uint16(str2num(get(handles.edit_NumFirstDCTCoefs, 'String'))); % проверить, чтобы число оставляемых коэффициентов было не больше % числа коэффциентов в блоке. Если что – скорректировать if (Params.NumFirstDCTCoefs > Params.BlockSize*Params.BlockSize ) Params.NumFirstDCTCoefs = Params.BlockSize*Params.BlockSize; set(handles.edit_NumFirstDCTCoefs, 'String', num2str(Params.NumFirstDCTCoefs)); end end %------------------------------------------------------------------
%-----------------------------------------------------------------% --- Отображение всех ДКП-поверхностей для иллюстрации % --- Вызывается при нажатии на кнопку pushbutton_ShowDCTCoefs %-----------------------------------------------------------------function pushbutton_ShowDCTCoefs_Callback(hObject, eventdata, handles) global Params % для наглядности вводим коэффициент "растяжения" поверхности % (масштабирования по горизонтали) resolution = 10; % считать с формы параметры кодирования read_params(hObject, eventdata, handles); figure;
% открываем новое окно
N = Params.BlockSize; for k = 1:N for l = 1:N subplot( N, N,(k-1)*N+l ); % выбираем часть окна для вывода графика % формируем матрицу для получения формы базисной функции in = zeros(N*resolution); in(k,l) = 1; % "тестовый сигнал" для оценки отклика % выполнить прямое ДКП out = dct2(in); mesh(out); % вывести в заданной части окна axis off; % отключить вывод числовых осей на графике end end %-----------------------------------------------------------------
51
%--------------------------------------------------------% --- Отображение всех коэффициентов масштабирования для иллюстрации % --- Вызывается при нажатии на кнопку pushbutton_ShowQuantCoefs %--------------------------------------------------------function pushbutton_ShowQuantCoefs_Callback(hObject, eventdata, handles) global Params % считать с формы параметры кодирования read_params(hObject, eventdata, handles); % рассчитать и показать коэффициенты квантования на отдельной форме figure; bar3(Generate_Scales(Params.BlockSize, Params.Quality)); %------------------------------------------------------------------
%-----------------------------------------------------------------% --- Выполнить процедуру кодирования изображения % --- Вызывается при нажатии на кнопку pushbutton_RunCoding %-----------------------------------------------------------------function pushbutton_RunCoding_Callback(hObject, eventdata, handles) global Params global SrcImage global DstImage global DCT_Image global DeScaleDCT_Image % читаем размеры изображения Params.ImageSize = size(SrcImage); % взять остальные параметры кодирования read_params(hObject, eventdata, handles); % Проверить размеры изображения на кратность заданым размерам блока ДКП % если есть хотя бы один ненулевой остаток от деления размера изображения % на размер блока ДКП - то ничего не делать if (any(rem(Params.ImageSize, Params.BlockSize))) return end Params.NumBlocks = uint16(Params.ImageSize / Params.BlockSize); % количество блоков % показать сообщение о начале кодирования set(handles.text_CodingProgress, 'String', 'Выполняется кодирование...'); drawnow; % принудительно вывести на экран %----- КОДЕР ------% выполнить кодирование DCT_Image = Im2DCT(SrcImage); % прямое ДКП Scale_Image = DCT2Scale(DCT_Image); % квантование коэффициентов ДКП % выстроить коэффициенты в вектор Linear_Coefs = Scale2Zigzag(Scale_Image); % обойти матрицу зигзагом % обрезать коэффициенты (обнулить лишние) [Cut_Coefs, NumC] = CutCoefs(Linear_Coefs); % оставить сколько надо коэффициентов %---- КОНЕЦ КОДЕРА ------% оценить коэффициент компрессии: размер исходного изображения в битах % делить на размер сжатых даных Params.CompressionRatio = (Params.ImageSize(1)*Params.ImageSize(2)*8) / EstimateBitRate(Cut_Coefs); %----- ДЕКОДЕР ------DeScale_Image = Zigzag2Scale(Cut_Coefs); DeScaleDCT_Image = Scale2DCT(DeScale_Image);
% сворачивание матрицы из вектора коэффициентов % деквантование коэффициентов ДКП
52
DstImage = DCT2Im(DeScaleDCT_Image); %---- КОНЕЦ ДЕКОДЕРА -------
% обратное ДКП
% оценить качество кодирования (сигнал-шум) Params.SN_ratio = SNR(SrcImage, DstImage); % показать восстановленное изображение axes(handles.axes_DstImage); imshow(DstImage, [0 255]);
% активируем нужный элемент управления % выводим в него изображение
% показать коэффициент компрессии set(handles.text_CompressionRatio, 'String', ... strcat('Коэффициент компрессии изображения (раз) = ', ... num2str(Params.CompressionRatio))); set(handles.text_SNR, 'String', strcat('Отношение сигнал/шум (дБ) = ', ... num2str(Params.SN_ratio))); % вывести сообщение об окончании кодирования set(handles.text_CodingProgress, 'String', 'Кодирование завершено'); %---------------------------------------------------------------------
%--------------------------------------------------------------------% --- Выполнение ДКП для изображения %--------------------------------------------------------------------function [out_image] = Im2DCT(in_image) global Params out_image = zeros(Params.ImageSize);
% создаем матрицу для хранения ДКП
% проходим по всем блокам заданного размера d = uint16(Params.BlockSize); % d – размер блока по каждой оси % в цикле используем векторизацию – за один раз рассчитываем % сразу целый блок благодаря использованию конструкций [1:d] for m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали out_image(m*d+[1:d], n*d+[1:d]) = dct2(in_image(m*d+[1:d], n*d+[1:d])); end end %---------------------------------------------------------------------
%--------------------------------------------------------------------% --- Выполнение обратного ДКП для изображения %--------------------------------------------------------------------function [out_image] = DCT2Im(in_image) global Params out_image = zeros(Params.ImageSize);
% создаем матрицу для хранения восст. изображения
% проходим по всем блокам заданного размера d = uint16(Params.BlockSize); % d – размер блока по каждой оси % в цикле используем векторизацию – за один раз рассчитываем % сразу целый блок благодаря использованию конструкций [1:d] for m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали out_image(m*d+[1:d], n*d+[1:d]) = idct2(in_image(m*d+[1:d], n*d+[1:d])); end end %---------------------------------------------------------------------
53
%--------------------------------------------------------------------% --- Масштабирование ДКП-коэффициентов %--------------------------------------------------------------------function [out_image] = DCT2Scale(in_image) global Params out_image = zeros(Params.ImageSize); % создаем матрицу для квант. коэффициентов % сгенерировать коэффициенты масштабирования coef_scales = Generate_Scales(Params.BlockSize, Params.Quality); d = uint16(Params.BlockSize); % d – размер блока по каждой оси % проходим по всем блокам заданного размера for m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали out_image(m*d+[1:d], n*d+[1:d]) = round(in_image(m*d+[1:d], n*d+[1:d]) ... ./ coef_scales); % округлить после деления end end %---------------------------------------------------------------------
%--------------------------------------------------------------------% --- Демасштабирование ДКП-коэффициентов %--------------------------------------------------------------------function out_image = Scale2DCT(in_image) global Params out_image = zeros(Params.ImageSize); % создаем матрицу для хранения восст. коэффициентов % сгенерировать коэффициенты масштабирования coef_descales = Generate_Scales(Params.BlockSize, Params.Quality); d = uint16(Params.BlockSize); % d – размер блока по каждой оси % проходим по всем блокам заданного размера for m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали out_image(m*d+[1:d], n*d+[1:d]) = in_image(m*d+[1:d], n*d+[1:d]) .* coef_descales; end end %---------------------------------------------------------------------
%---------------------------------------------------------------------% --- Обход матрицы зигзагом и вытаскивание коэффициентов в вектор %---------------------------------------------------------------------function linear_coefs = Scale2Zigzag(in_image) global Params % заранее выделить место под линейное хранение коэффициентов % двумерный массив. Число строк – полное число блоков, число столбцов – % количество элементов в блоке linear_coefs = zeros(Params.NumBlocks(1)*Params.NumBlocks(2), ... Params.BlockSize*Params.BlockSize); % сформировать последовательность индексов для обхода зигзагом % формируются индексы и в матричной форме и в линейной (для самопроверки) % после тестирования достаточно оставить только линейную форму [zigzag_ind, zigzag_ind_l] = Generate_Zigzag(Params.BlockSize); % проходим по всем блокам заданного размера d = uint16(Params.BlockSize); % d – размер блока по каждой оси
54
t = d*d; % t – число элементов в блоке p = 1; % храним в новом массиве for m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали ttt = UnrollMatrix(in_image(m*d+[1:d], n*d+[1:d]), zigzag_ind, zigzag_ind_l); linear_coefs(p, :) = ttt; % запомнить результат p = p+1; % перейти к следующему блоку end end %---------------------------------------------------------------------
%--------------------------------------------------------------------% --- Проход вектора и формирование матрицы зигзагом %--------------------------------------------------------------------function out_image = Zigzag2Scale(linear_coefs) global Params % заранее выделить место под матрицу out_image = zeros(Params.ImageSize(1),Params.ImageSize(2)); % сформировать последовательность индексов для обхода зигзагом % формируются индексы и в матричной форме и в линейной (для самопроверки) % после тестирования достаточно оставить только линейную форму [zigzag_ind, zigzag_ind_l] = Generate_Zigzag(Params.BlockSize);
d = t = p = for
% проходим по всем блокам заданного размера uint16(Params.BlockSize); % d – размер блока по каждой оси d*d; % t – число элементов в блоке 1; % храним в новом массиве m = 0:Params.NumBlocks(1)-1 % количество блоков по вертикали for n = 0:Params.NumBlocks(2)-1 % количество блоков по горизонтали out_image(m*d+[1:d], n*d+[1:d]) = RollMatrix(linear_coefs(p, :), ... zigzag_ind, zigzag_ind_l); p = p+1; end
end %--------------------------------------------------------------------
%-------------------------------------------------------------------% --- Обрезание числа коэффициентов %-------------------------------------------------------------------function [cut_linear_coefs, num_coefs] = CutCoefs(linear_coefs) global Params % выделяем память под массивы "обрезанных" коэффициентов cut_linear_coefs = zeros(Params.NumBlocks(1)*Params.NumBlocks(2), ... Params.BlockSize*Params.BlockSize); % и под массив количества коэффициентов в каждом блоке num_coefs = zeros(Params.NumBlocks(1)*Params.NumBlocks(2),1); % вспомогательные временные переменные – для краткости d = uint16(Params.BlockSize); t = d*d; % в зависимости от установленного способа кодирования коэффициентов ДКП switch Params.CodeNonZero case 0 % кодировать заданное число коэффициентов % строим маску, одинаковую для всех блоков mask = ones(1, Params.NumFirstDCTCoefs); if Params.NumFirstDCTCoefs < t add_mask = zeros(1, t-Params.NumFirstDCTCoefs); mask = [mask add_mask];
55
end % проходим по всем блокам заданного размера for m = 1:Params.NumBlocks(1)*Params.NumBlocks(2) % количество линейных блоков cut_linear_coefs(m, :) = linear_coefs(m, :) .* mask;% обнуляем лишние коэффициенты num_coefs(m+1) = Params.NumFirstDCTCoefs; % количество коэффициентов !=0 end case 1 % кодировать все ненулевые коэффициенты % проходим по всем блокам заданного размера for m = 1:Params.NumBlocks(1)*Params.NumBlocks(2) % количество линейных блоков % находим индекс последнего коэффициента, неравного 0 last_non_zero_ind = find(linear_coefs(m, :), 1, 'last'); % строим маску с необходимым числом единиц и нулей if (last_non_zero_ind == t) % чтобы в цикле избежать изменения размера mask = ones(1, last_non_zero_ind); elseif isempty(last_non_zero_ind) % хотя бы один коэффициент должен быть last_non_zero_ind = 1; mask = [ones(1, last_non_zero_ind) zeros(1, t-last_non_zero_ind)]; else mask = [ones(1, last_non_zero_ind) zeros(1, t-last_non_zero_ind)]; end cut_linear_coefs(m, :) = linear_coefs(m, :) .* mask; % обнуляем лишние коэффициенты num_coefs(m+1) = last_non_zero_ind; % количество коэффициентов !=0 end end %----------------------------------------------------------------------
%---------------------------------------------------------------------% --- Оценка размера компрессированных данных %---------------------------------------------------------------------function [c_ratio] = EstimateBitRate(cut_linear_coefs) global Params c_ratio = 0; % сформировать примерные длины кодов Хаффмана table_code_len = Generate_Scales(Params.BlockSize*Params.BlockSize, 0); % проходим по всем блокам заданного размера pDC = 0; % последний DC-коэф. сначала = 0 for m = 1:Params.NumBlocks(1)*Params.NumBlocks(2) % количество линейных блоков % рассчитать размер каждого блока s = EstimateBlockBitRate(cut_linear_coefs(m, :), pDC, table_code_len); pDC = cut_linear_coefs(m, 1); % запомнить последний DC c_ratio = c_ratio + s; % суммируем по всему изображению end %----------------------------------------------------------------------
%----------------------------------------------------------------------% --- Обработка нажатия кнопки мыши над формой. Используется для выбора % --- блока на исходном изображении и вывода детальной информации о его % --- кодировании %----------------------------------------------------------------------function figure1_WindowButtonDownFcn(hObject, eventdata, handles) global Params global SrcImage global DstImage global DCT_Image global DeScaleDCT_Image % определяем попадание координат в область исходного изображения pt = get(handles.axes_SrcImage, 'currentpoint');
56
cp(1,1) = pt(1, 2); cp(1,2) = pt(1, 1); % по смещению от начала области изображения определяем номер блока num_block = floor(cp ./ Params.BlockSize); % показать исходный блок SrcBlockImage = SrcImage(num_block(1)*(Params.BlockSize) + [1:Params.BlockSize], ... num_block(2)*(Params.BlockSize) + [1:Params.BlockSize]); axes(handles.axes_SrcBlock); % активируем нужный элемент управления imshow(SrcBlockImage, [0 255]); % выводим в него изображение % показать восстановленный блок DstBlockImage = DstImage(num_block(1)*(Params.BlockSize) + [1:Params.BlockSize], ... num_block(2)*(Params.BlockSize) + [1:Params.BlockSize]); axes(handles.axes_DstBlock); % активируем нужный элемент управления imshow(DstBlockImage, [0 255]); % выводим в него изображение % показать таблицу исходных коэффициентов ДКП d = uint16(Params.BlockSize); % количество элементов в стороне блока hdr_c = cell(1, Params.BlockSize); % место под заголовки столбцов width_c = cell(1, Params.BlockSize); % место под ширины столбцов hdr_r = cell(Params.BlockSize, 1); % место под заголовки строк for i=1:Params.BlockSize hdr_c{1, i} = num2str(i); % заголовки – просто номера строк и столбцов width_c{1, i} = 'auto'; % ширина – "автоподбор" hdr_r{i, 1} = num2str(i); end % установить параметры обеих таблиц одинаковыми % исходные коэффициенты set(handles.uitable_TableSrcBlock, 'ColumnName', hdr_c); set(handles.uitable_TableSrcBlock, 'ColumnWidth', width_c); set(handles.uitable_TableSrcBlock, 'RowName', hdr_r); set(handles.uitable_TableSrcBlock, 'Data', DCT_Image(num_block(1)*d+[1:d], ... num_block(2)*d+[1:d])); % коэффициенты после квантования-деквантования set(handles.uitable_TableDstBlock, 'ColumnName', hdr_c); set(handles.uitable_TableDstBlock, 'ColumnWidth', width_c); set(handles.uitable_TableDstBlock, 'RowName', hdr_r); set(handles.uitable_TableDstBlock, 'Data', DeScaleDCT_Image(num_block(1)*d+[1:d], ... num_block(2)*d+[1:d])); %------------------------------------------------------------------------
%------------------------------------------------------------------------% --- Вывести исходное изображение в отдельном окне % --- Вызывается при нажатии на кнопку pushbutton5 %------------------------------------------------------------------------function pushbutton5_Callback(hObject, eventdata, handles) % hObject handle to pushbutton5 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) global SrcImage figure; % новое окно imshow(SrcImage, [0 255]); % принудительно установить диапазон амплитуд для double %-------------------------------------------------------------------------
%-------------------------------------------------------------------------
57
% --- Вывести декодированное изображение в отдельном окне % --- Вызывается при нажатии на кнопку pushbutton6 %------------------------------------------------------------------------function pushbutton6_Callback(hObject, eventdata, handles) % hObject handle to pushbutton6 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) global DstImage figure; % новое окно imshow(DstImage, [0 255]); % принудительно установить диапазон амплитуд для double %-------------------------------------------------------------------------
%------------------------------------------------------------------------% --- Оценить значение полосы прокрутки и вывести в текстовое поле % --- Вызывается при смещении ползунка %------------------------------------------------------------------------function slider_Quality_Callback(hObject, eventdata, handles) % параметр качества кодирования st = round(get(hObject, 'Value')); % вывести в числовом виде в более понятном представлении % 1 – мин, 100 – макс set(handles.text_Quality, 'String', num2str(100-st+1)); %-------------------------------------------------------------------------
%------------------------------------------------------------------------% Приведенные ниже функции (шаблоны) сгенерированы GUIDE и при разработке % программы не использовались и не модифицировались %------------------------------------------------------------------------function edit_Quality_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
function slider_Quality_CreateFcn(hObject, eventdata, handles) if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end
function edit4_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
function listbox1_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
function popupmenu_BlockSize_Callback(hObject, eventdata, handles)
function popupmenu_BlockSize_CreateFcn(hObject, eventdata, handles)
58
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
function edit_NumFirstDCTCoefs_Callback(hObject, eventdata, handles)
function edit_NumFirstDCTCoefs_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end
function edit_DCTCoefsBitRate_Callback(hObject, eventdata, handles)
function edit_DCTCoefsBitRate_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end %------------------------------------------------------------------------
Задания на лабораторную работу Разработать программу, выполняющую компрессию и декомпрессию цветного изображения. При кодировании программа должна выполнять несколько этапов обработки: 1) перевод изображения из цветового пространства RGB в другое пространство в соответствии с вариантом заданием 2) понижение частоты дискретизации одной или двух компонент в соответствии с вариантом задания 3) обработка каждой компоненты с использованием некоторого преобразования (согласно варианту задания) с целью декорреляции элементов изображения 4) выбор наиболее значимых коэффициентов преобразования и отбрасывание остальных алгоритмов (по собственному алгоритму, у которого должен быть варьируемый параметр) 5) для заданного фиксированного числа битов на каждый коэффициент оценить планируемый размер закодированного изображения (не выполняя кодирования коэффициентов) При декодировании порядок выполнения этапов, соответственно, обратный. После декодирования необходимо оценить степень соответствия восстановленного изображения исходному (качество кодирования). Вариант Цветовое Фактор Вид преобразования Размеры блоков № пространство передискретизации 1 YIQ 4:1:1 Дискретно-синусное 4х4, 8х8, 16х16 Дискретное 2 YCbCr 4:1:2 8х8, 16х16 преобразование Фурье 4х4, 8х8, 16х16, 3 CIE Lab 4:2:1 Хаара 32х32 59
Вариант Цветовое № пространство
Фактор передискретизации
Вид преобразования
4
YIQ
4:2:2
Уолша-Адамара
5
YCbCr
4:2:1
Карунена-Лоэва
6
CIE Lab
4:1:2
Хотеллинга
Размеры блоков 4х4, 8х8, 16х16, 32х32 компонента целиком компонента целиком
По результатам выполнения лабораторной работы провести эксперименты по оценке влияния параметра алгоритма отбора наиболее значимых коэффициентов преобразования на качество кодирования и степень компрессии.
60