| anonymous@RULINUX.NET~# | Last login: 2025-11-16 17:14:39 |
| Регистрация Вход | Новости | Разметка | Пользователи | Галерея | Форум | Статьи | Неподтвержденное | Трекер | Правила форума | F.A.Q. | Ссылки | Поиск |
| Статьи - Development | [RSS] |
samolet | Предыдущая | Извлечение пикселей | подсчет объектов | | wavelet
Извлечение пикселей из картинки при помощи ImageMagick и показ картинки в виждете gtk2-perl.
Gtk2-perl позволяет получить доступ к пикселям при помощи функции get_pixels, которая возвращает 16-ти битную строку пикселей длины w*h*3 для RGB изображения. Единственное неудобство в том, что функции для работы с изображениями Gtk2-perl понимают несколько форматов картинок, а ImageMagick позволяет работать с более чем 90 форматами изображений. Функция Gtk2::Gdk::Pixbuf->new_from_data может из строки в 16-тиричном формате выстраивать картинку. Значит для этого надо открыть картинку, прочитать пикселы и затем сформировать и передать в perl соответствующую строку при помощи библиотеки ImageMagick.
Для начала необходимо написать программу на c, после чего уже писать соответствующий XS-модуль. Программа выглядит как-то так:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// подключить API ImageMagick
#include <magick/api.h>
int main(int argc,char **argv) {
//Воспользоваться внутренними типами IM
ExceptionInfo
exception;
Image
*image;
ImageInfo
*image_info;
PixelPacket
*pixels;
ViewInfo
*vinfo;
int i,j,w,h;
// Инициализировать структуру image info и прочитать изображение
InitializeMagick(*argv);
// установить обработку событий типа ReadError и т.п.
GetExceptionInfo(&exception);
// сделлать копию структуры image info
image_info=CloneImageInfo((ImageInfo *) NULL);
// скопировать в структуру имя файла
(void)strcpy(image_info->filename,"image.gif");
// прочитать картинку, попутно отработав эксепшены &exception
image=ReadImage(image_info,&exception);
if (image == (Image *) NULL) {
// в случае ошибки
fprintf(stderr, "readFileMagick: %s: %s\n",
exception.reason,exception.description);
// MagickError(exception.severity,exception.reason,exception.description);
return -1;
}
// открыть открыть просмотр кеша пикселей
vinfo = OpenCacheView(image);
pixels = GetCacheView(vinfo, 0,0,image->columns,image->rows);
if(!pixels) {
fprintf(stderr, "readFileMagick: ошибка чтения кеша пикселей.\n");
return(-1);
}
h = image->columns; //ширина по горизонтали (число столбцов картинки)
w = image->rows; //высота по вертикали (число строк картинки)
// вывести значения пикселов по трем каналам
for (i = 0; i <= w-1; i++) {
for (j = 0; j <= h-1; j++) {
printf("%d ",(int)255*pixels[j+h*i].blue/65535);
printf("%d ",(int)255*pixels[j+h*i].green/65535);
printf("%d\n",(int)255*pixels[j+h*i].red/65535);
}
}
// закрыть и уничтожить все
CloseCacheView(vinfo);
DestroyImageInfo(image_info);
DestroyImage(image);
return(0);
}
компилировать программу можно таким образом:
setenv LD_LIBRARY_PATH /usr/local/lib
gcc `Magick-config --cflags --cppflags` pixels.c `Magick-config --ldflags --libs`
Требования к функции, возвращающей пикселы, следующие: имя файла должно
передаваться в качестве параметра и в нагрузку параметр для чегонибудь
сделания с извлекаемыми пикселами. Функция должна возвращать строку пикселей в
16-тиричном виде и высоту + ширину картинки, необходимые для new_from_data().
Чтобы получить имя картинки в XS, можно воспользоваться следующим
подходом:
SV*
pixs (SV * fn, int k)
INIT:
unsigned char * lfn;
STRLEN l; /* STRLEN is a certain type of int */
/* ... */
CODE:
lfn = SvPV (fn, l);
после этого имя картинки будет содержаться в переменной lfn.
В целом, на XS вышеприведенная программа выглядит таким образом:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
// string.h нужен для функции strcpy
#include <string.h>
// на всякий случай, для матобработкию. если таковая будет, чтобы не писать при компиляции -lm
#include <math.h>
// для ImageMagick
#include <magick/api.h>
#include "ppport.h"
// определить название модуля, необходимого далее для инициализации ImageMagick
#define PackageName "Pixels"
// название модуля и пакетов
MODULE = Pixels PACKAGE = Pixels
// отключить прототипы, о(see perldoc perlxs)
PROTOTYPES: DISABLE
// Инициализировать ImageMagick (see perldoc perlxs)
BOOT:
InitializeMagick(PackageName);
// скаляр (see perldoc perlguts), функции передаются на вход два параметра,
// имя файла и что-то еще. Тип передаваемых параметров определяется только десь
SV*
pixs(SV *fn, int k)
INIT:
//Воспользоваться внутренними типами IM
ExceptionInfo
exception;
Image
*image;
ImageInfo
*info,
*image_info;
PixelPacket
*pixels;
ViewInfo
*vinfo;
// определить двумерные массивы для хранения пикселов
int **sm,**sym,i,j;
// переменные для имени файла и возвращаемого значения пикселов
unsigned char * lfn, * number;
// определение STRLEN находится в файле config.h (perldoc perlguts)
STRLEN t;
// определение типа данных для хеша и для массива *только для XSUBs* (perldoc perlguts)
HV* hash = newHV();
AV* array = newAV();
CODE:
// присваивание имени, впрочем, это описано в perldoc perlguts
lfn = SvPV (fn,t);
// установить обработку событий типа ReadError и т.п.
GetExceptionInfo(&exception);
// сделлать копию структуры image info
image_info=CloneImageInfo((ImageInfo *) NULL);
// скопировать в структуру имя файла
strcpy(image_info->filename, lfn);
// прочитать картинку, попутно отработав эксепшены &exception
image=ReadImage(image_info,&exception);
// в случае ошибки
if (image == (Image *) NULL) {
fprintf(stderr, "readFileMagick: %s: %s\n",
exception.reason,exception.description);
}
// открыть просмотр кеша пикселей
vinfo = OpenCacheView(image);
pixels = GetCacheView(vinfo, 0,0,image->columns,image->rows);
int h=image->columns; //ширина по горизонтали (число столбцов)
int w=image->rows; //высота по вертикали (число строк)
// занести данные о высоте и ширине картинки в массив, который будет
// сопоставлен с ключом хеша arr
av_push(array, newSVnv(h));
av_push(array, newSVnv(w));
int small=w*h*3;
// выделение памяти для строки возвращаемых пикселов, длина строки должна
// быть равна определенной выше small.
number=malloc(small*sizeof(*number));
// отработка ошибки, если возникнут проблемы с pixels
if(!pixels) {
fprintf(stderr, "readFileMagick: unable to get pixel cache.\n");
}
// выделение памяти для двумерных массивово
sm = malloc(w * sizeof(*sm));
for (i=0; i<w; ++i){
sm[i] = malloc ( h * sizeof(**sm));
}
sym = malloc(w * sizeof(*sym));
for (i=0; i<w; ++i){
sym[i] = malloc ( h * sizeof(**sym));
}
// заполнение массива пикселей для дальнейшей обработки
for (i=0; i<=w-1; i++) {
for (j=0; j<=h-1; j++) {
sm[i][j]=(int)255*pixels[j+h*i].blue/65535;
sym[i][j]=sm[i][j];
}
}
// математическая обработка пикселей, алгоритм подробно описан здесь и здесь немного
for (i=k; i<=w-1-k; i++){
for (j=k; j<=h-1-k; j++){
int summ=0;
int ii,jj;
for (ii=-k; ii<=k; ii++){
for (jj=-k; jj<=k; jj++) summ+=sm[i+ii][j+jj];
}
sym[i][j]=(int)summ/((2*k+1)*(2*k+1));
}
}
int count=0;
// заполнение массива пикселей, которые будут возвращаться в perl-программу по ключу хеша uns
for (i=0; i<=w-1; i++){
for (j=0; j<=h-1; j++){
number[count]=(unsigned char)sym[i][j];
count++;
number[count]=(unsigned char)sym[i][j];
count++;
number[count]=(unsigned char)sym[i][j];
count++;
}
//освободить память из под массивов
free (sm[i]);
free (sym[i]);
}
free(sm);
free(sym);
// закрыть и уничтожить все
CloseCacheView(vinfo);
DestroyImageInfo(image_info);
DestroyImage(image);
// добавить в значение хеша массив
hv_store(hash, "arr",3,(SV*)array, 0);
// добавить в значение хеша строку unsigned char, которая ассоциируется с ключем uns
// четвертым параметром идет выделение памяти для переменной number
hv_store(hash, "uns",3, newSVpv ((unsigned char*) number, small*sizeof(number[0])), 0);
free(number);
RETVAL = newRV_noinc((SV*) hash);
// прагма (?) RETVAL возвращает ссылку на хеш (perldoc perlguts).
OUTPUT:
RETVAL
Чтобы сделать модуль, который будет вызываться в perl-программе, нужно
сделать следующее:
[vilfred@mobile100 xxx]$ h2xs -A -n Pixels Defaulting to backwards compatibility with perl 5.8.3 If you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option. Writing Pixels/ppport.h Writing Pixels/lib/Pixels.pm Writing Pixels/Pixels.xs Writing Pixels/Makefile.PL Writing Pixels/README Writing Pixels/t/Pixels.t Writing Pixels/Changes Writing Pixels/MANIFEST [vilfred@mobile100 xxx]$Эта команда создаст каталог со всеми необходимыми для компиляции и дальнейшего использования файлами. Т.к. компилирование c-шного файла требовало подключения библиотек ImageMagick, то нужно подправить Makefile.PL:
LIBS => ['-L/usr/lib -lMagick -L/usr/X11R6/lib -lfreetype -lz \
-L/usr/lib -ltiff -lfreetype -ljpeg -lXext -lSM -lICE -lX11 -lXt \
-lbz2 -lz -lpthread -lm -lpthread'], # e.g., '-lm'
После этого вносятся соответствующие правки в текст Pixels.xs и далее идут команды perl Makefile.PL, make и make test. Т.к. модуль Pixels.pm не установлен (не было команды make install), то необходимо вновь написанный модуль каким-то образом вызвать в perl-скрипте. Nick Ing-Simmons написал библиотеку blib (perldoc blib), которая находит необходимый модуль.
Соответствующий perl-код такой,(с подсвеченным синтаксисом html). Вобщем, что то в этом роде...
samolet | Предыдущая | Извлечение пикселей | to be continued...
vilfred(*) (2010-03-04 20:43:00)
Подтверждено: vilfred(*) (2010-03-04 20:43:00)
|
|
|
| Этот тред читают 1 пользователь: |
|
Анонимных: 1 Зарегистрированных: 0 |