}
}
Следующий листинг 3.15 содержит код, который выполняет передачу данных. Метод sendImageViaBluetooth получает массив байт, который представляет собой изображение.
Листинг 3.15 – Отправкаизображенияпо Bluetooth
publicstaticvoidsendImageViaBluetooth (byte[] data) {
OutputStream btOutStr = null;
try {
StreamConnection conn = null;
String connectionURL = Preferences.getInstanse().getBTConnectionURL();
if (connectionURL == "") {
Log.out.println ("connectionURL is empty");
return;
}
try {
conn = (StreamConnection) Connector.open(connectionURL);
} catch (IOException e) {
Log.out.println (" sendImageViaBluetooth" + e.toString());
}
btOutStr = conn.openOutputStream();
btOutStr.write(data);
btOutStr.close();
} catch (IOException ex) {
Log.out.println ("sending image via BT failed (IOException)" + ex.toString());
} catch (Throwable th) {
Log.out.println ("sending image via BT failed" + th.toString());
} finally {
try {
btOutStr.close();
} catch (IOException ex) {
Log.out.println ("IOException while closing stream" + ex.toString());
}
}
}
Прием и отображение полученного кадра выполняется аналогичным способом на другом телефоне. Соответствующий код представлен в приложении А.
На следующем рисунке 3.6 приведен пример получения клиентом изображения по Bluetooth и отображения его на форме.
Рисунок 3.6 – Передача данных по Bluetooth
3.4 Работа с файловой системой телефона
В конфигурации CLDC отсутствует API для работы с файловой системой и внешними картами памяти телефона, т. к. не у каждого устройства с профилем MIDP есть файловая система.
Платформа J2SE включает в себя java.io. File и сопутствующие классы, но эти пакеты слишком тяжеловесны для мобильных устройств. Для работы с файлами в мобильных устройствах разработан пакет JSR-75 [10], который предоставляет простой и легковесный FileConnection API для работы с файловой системой. FileConnection API позволяет приложениям создавать, выполнять чтение и запись в файлы и директории, размещенные на телефоне или карте памяти. Основные классы и интерфейсы пакета JSR-75 следующие:
- интерфейс FileConnection – для доступа к файлам и директориям;
- интерфейс FileSystemListener – для прослушивания извещения о добавлении или удалении корневых директорий;
- класс FileSystemRegistry – центральный реестр для слушателей о добавлении или удалении корневых файловых систем;
- класс ConnectionClosedException – исключение, которое выбрасывается в случае невозможности выполнения методов FileConnection по причине закрытия соединения;
- класс IllegalModeException – исключение, которое выбрасывается в случае выполнения методов, требующих особых режимов безопасности, таких как READ или WRITE, но FileConnection открыт в другом режиме.
Приложение может открыть соединение, используя метод Connector.open(). Его единственный параметр – URL, содержащий полный путь к файлу специального формата: file:// <host>/<root>/<directory>/<directory>/…/<fileName>. Элемент host может быть пустым.
Список доступных корневых директорий устройства можно получить с помощью вызова метода FileSystemRegistry.listRoots().
Установив соединение FileConnection с файлом или каталогом, можно выполнять следующие действия:
- определять, куда указывает соединение FileConnection – на файл или папку – с помощью метода isDirectory();
- получать фильтрованный список файлов и директорий методом list (String filter, boolean includeHidden);
- проверять, существует ли директория или файл, применяя метод exists();
- определять, является ли скрытым файл, используя метод isHidden();
- создавать, удалять файл или директорию методами create(), mkdir() и delete();
- открывать входной / выходной поток для чтения / записи данных в файл, применяя методы openInputStream(), openOutputStream().
Листинг разработанного навигатора по файловой системе мобильного телефона представлен в приложении Б.
На рисунке 3.7 приведен пример отображения одного их каталогов файловой системы телефона.
Рисунок 3.7 – Файловый броузер
Для отправки сообщений с мобильного телефона было использовано Wireless Messaging API 2.0 (пакет javax.wireless.messaging) [11]. Основные классы этого пакета следующие:
- MessageConnection – интерфейс, который определяет операции для посылки и получения сообщений;
- TextMessage – интерфейс, представляющий текстовые сообщения;
- MultipartMessage – интерфейс для представления составных сообщений;
- MessagePart – экземпляры данного класса могут быть добавлены в MultipartMessage. Каждый MessagePart состоит из данных.
Для отправки сообщений приложение должно сначала получить экземпляр MessageConnection, передав методу javax.microedition.io. Connector.open() URL, определяющий адресат. В этом URL содержится информация об используемом протоколе (SMS или MMS), номере телефона и порте адресата.
После создания MessageConnection формируется SMS или MMS-сообщение, заполняется данными и отправляется на указанный номер (листинги 3.16 и 3.17).
Листинг3.16 – ОтправкаSMS-сообщений
* Send SMS with specified text to phoneNumber
public static void sendSMS (String phoneNumber, String text) {
try {
String addr = "sms:// " + phoneNumber+":5678";
MessageConnection conn = (MessageConnection) Connector.open(addr);
TextMessage msg = (TextMessage) conn.newMessage (MessageConnection.TEXT_MESSAGE);
msg.setPayloadText(text);
conn.send(msg);
conn.close();
} catch (IOException ex) {
Log.out.println ("IOException at Utilities.sendSMS()" + ex.toString());
}
}
Листинг3.17 – Отправка MMS-сообщений
* Send MMS with specified image in second parameter to phoneNumber
*/
public static void sendMMS (String phoneNumber, byte[] data) {
try {
private static MessageConnection conn;
private static MultipartMessage msg;
String addr = "mms:// " + phoneNumber +":5432";
conn = (MessageConnection) Connector.open(addr);
msg = (MultipartMessage) conn.newMessage (MessageConnection.MULTIPART_MESSAGE);
// size of the part and the number of bytes loaded to mms
int partSize = 10000, counter = 0;
byte buf[] = new byte[partSize];
for (int i = 0; i < data.length / partSize && counter<=290000; i++) {
int curPartLength = partSize;
// if the number of left bytes in data[] is lenss then part size
if (counter + partSize > data.length) {
buf = new byte [data.length – counter];
curPartLength = data.length – counter;
}
// load next part of mms
for (int j = 0; j < curPartLength; j++) {
buf[j] = data [counter++];
}
MessagePart p = new MessagePart (
buf,
Preferences.getInstanse().getEncodingType(),
String.valueOf(i), null, null);
msg.addMessagePart(p);
}
} catch (SizeExceededException ex) {
Log.out.print ("SizeExceededException "+ex.toString());
} catch (Exception e) {
Log.out.print ("Exception "+e.toString());
} finally {
try {
conn.send(msg);
conn.close();
} catch (IOException ex) {
Log.out.print ("IOException "+ex.toString());
}
}
}
Для указания номера, на который необходимо отправлять сообщения с уведомлениями об обнаруженном движении или о возможных ошибках в работе, разработаны две формы (рисунок 3.8).
Рисунок 3.8 – Настройка SMS и MMS-уведомлений
Алгоритм обнаружения движения основан на сравнении последовательных кадров, которые получаются от камеры с использованием MobileMediaAPI[12] следующим образом (листинг 3.18).
Листинг3.18 – Доступккамере
player = Manager.createPlayer ("capture://video");
player.realize();
videoControl = (VideoControl) getPlayer().getControl ("VideoControl");
videoControl.setDisplayFullScreen(true);
byte[] b = new byte[5000];
// get snapshot
b = videoControl.getSnapshot(encodings);
im = Image.createImage (b, 0, b.length);
rgbIm = new RGBImage(im);
// call method for motion detection
int r = process (rgbIm.getRGB());
На рисунке 3.9 приведена диаграмма деятельности, которая описывает процесс видеонаблюдения.
Функция обнаружения движения получает в качестве параметра очередной кадр камеры, который представляет собой одномерный массив. Каждый элемент массива – это одна точка изображения в формате AARRGGBB, который обозначает следующее:
- AA – прозрачность (0xFF означает полную непрозрачность, а 0 – полную прозрачность);
- RR, GG, BB – соответственно красная, зеленая, голубая rgb-составляющие цвета данной точки.
Обнаружение движения выполняется в несколько этапов. На первом сравниваются два последовательных кадра и формируется маска. Для этого подсчитывается средняя прозрачность всех точек двух сравниваемых кадров и определяется их разность (коррекция). Далее происходит сравнение соответствующих точек этих кадров и вычисляются разности rgb-составляющих цветов этих точек (листинг 3.19).
Эти разности затем корректируются, а именно: присваивается 0, если данная разность меньше коррекции, в противном случае – из данной разности вычитают коррекцию. Далее получают оттенок серого по скорректированным rgb-разностям, как показано в листинге 3.19 (вычисление переменной result). В результирующую маску записывается этот оттенок серого с учетом прозрачности alpha, взятой из соответствующей точки предыдущего кадра. Если в данных точках есть значительное изменение, то в маску записывается белая точка.
Листинг3.19 – Формированиемаски
// current image (inDataInt) and the previous one (refDataInt)
int alpha = refData[ip] & 0xFF000000;
refDataInt = (refData[ip] & 0xFF0000) / 256 / 256;
inDataInt = (inData[ip] & 0xFF0000) / 256 / 256;
r = (refDataInt > inDataInt)? refDataInt – inDataInt: inDataInt – refDataInt;
refDataInt = (refData[ip] & 0x00FF00) / 256;
inDataInt = (inData[ip] & 0x00FF00) / 256;
g = (refDataInt > inDataInt)? refDataInt – inDataInt: inDataInt – refDataInt;
refDataInt = (refData[ip] & 0x0000FF);
inDataInt = (inData [ip++] & 0x0000FF);
b = (refDataInt > inDataInt)? refDataInt – inDataInt: inDataInt – refDataInt;
// intensity normalization
r -= (r < correction)? r: correction;
g -= (g < correction)? g: correction;
b -= (b < correction)? b: correction;
result = (byte) (java.lang. Math.sqrt((double) ((r * r) + (g * g) + (b * b)) / 3.0));
// bwData is a mask
if (result > (byte) threshold) {
bwData [op++] = alpha + 0xFFFFFF;
} else {
bwData [op++] = alpha + result;
}
Далее анализируется полученная маска и подсчитывается количество областей, где рядом находящиеся точки красного цвета. На рисунке 3.10 показаны рядом находящиеся точки (отмечены символом "v") около текущей (обведена толстой линией). Если количество таких областей больше некоторого порога, то движение было обнаружено.
v | v | v |
v | v | v |
v | v | v |
Рисунок 3.10 – Анализ маски
Полный листинг метода обнаружения движения приведен в приложении В.
Рисунок 3.9 – Диаграмма деятельности для процесса видеонаблюдения
В дипломной работе освещены теоретические основы платформы J2ME, архитектуры Bluetooth и обработка видеоданных для обнаружения движения. Разработано приложение на платформе J2ME, которое позволяет осуществлять видеонаблюдение. В нем используются такие ресурсы мобильного телефона как файловая система, камера, Bluetooth, отправка SMS и MMS-сообщений. Изучена библиотека LWUIT, применяемая для построения графического интерфейса.