Несколько слов о PACS.

20.04.2009

Полагаю, мы должны начать с небольшого обзора, объяснив, почему PACS имеет важное значение в лучевой диагностике.
У методов лучевой диагностики есть несколько ограничивающих факторов:
1. Стоимость рабочего времени врачей.
2. Больничные площади, необходимые для размещения диагностической аппаратуры.
3. Стоимость проявления снимков
4. Штатное расписание.
Мы считаем, что PACS поможет решить эти проблемы следующим образом:
1. Стоимость рабочего времени врача - лучевого диагноста.
PACS делает ненужной огромное количество рутинной работы, которой сейчас занимаются врачи. например, больше не нужно возиться с пленками, вручную описывать результаты исследования (если вы до сих пор этим занимаетесь), нет постоянных задержек с поступлением снимков от рентгенологов , не приходится вручную искать информацию о пациентах в базах данных информационной системы и т.д. Подобного рода работа кажется мелочью, но на самом деле она отнимает огромное количество времени у высокооплачиваемых специалистов. Этой ненужной деятельности можно избежать с помощью цифровых технологий, с помощью интуитивно понятного интерфейса объединив доступ к полученному изображению и информации о пациенте. В результате квалифицированные специалисты смогут работать более эффективно, что позволит увеличить пропускную способность отделения лучевой диагностики или сократить количество сотрудников.
2. Больничные площади, необходимые для размещения аппаратуры.
Берем за основу предположение, что с использованием цифровых систем пропускная способность аппаратов возросла. Считается что одна DR система может работать с такой же эффективностью, как 3 аналоговых. Это позволит значительно сэкономить больничные площади. Впрочем, эффект может оказаться меньше ожидаемого из-за того, что при работе с PACS может понадобиться отдельное помещение для серверов.
3. Стоимость проявления снимков
После введения PACS эту статью расходов можно практически не принимать во внимание, теперь изображения будут обрабатываться и распространяться в цифровом формате. Тем не менее, на первых порах экономия будет перекрываться расходами на переход к DR- или CR- системам.
4. Штатное расписание.
Кадровые аспекты внедрения системы PACS могут оказаться весьма болезненны для сотрудников. Тем не менее, мы считаем, что персонал, занимавшийся ранее проявкой снимков, может в дальнейшем выполнять другие функции. Или, если таковых функций не находится, сотрудников можно сократить.
У PACS есть множество других преимуществ, о которых мы постараемся упомянуть как можно короче:

  • Возможность распространять изображение получать его копии, мгновенно передавать его врачам в палаты, другие больницы, врачам экстренных служб и так далее.
  • Позволяет передавать работу от одного врача другому, пользуясь единым централизованным списком.
  • Минимизировать брак, используя цифровые методы обработки изображения (изменение яркости, контрастности, цифровое увеличение резкости и т.д.)
  • Мгновенный доступ к результатам прошлых исследований.
  • Технологии распознавания речи (быстрый ввод информации)
  • Усиленная безопасность
  • Перевод в цифровую форму большинства бумажных документов (т.е. направлений на исследование)

Указатели в Delphi. Часть вторая.

20.04.2009

Операция @

Операция @ позволяет получить номер ячейки (адрес) переменной. В верхнем примере @i будет равно 54564786.

Операция p := @i занесёт данные об адресе переменной i в указатель p.

Значок ^.

Когда значок ^ стоит после названия переменной-указателя (p^), он обозначает, что указатель разыменовывают. Как я писал выше, обращаются не к данным в переменной p, а к данным, на которые указывает переменная p.
То есть p^ и i - одно и то же. Для нас. Но не для компилятора. Что бы компилятор понял, что можно делать с p^, что бы он знал, на что собственно указывает указатель (понятно, что он всегда указывает на какую-то ячейку памяти, но там может находиться начало любой переменной или объекта, а может не находится вообще ничего интересно, либо мусор, либо может быть ‘середина’ переменной, либо вообще кусок кода, а не данные. То есть, что в поинтер положили, на то он и указывает. А уж что конкретно там лежит, на что он указывает - известно только Богу. Если вы - хороший программист, то еще и вам), он должен быть типизированным. То есть он должен быть не pointer, а, например, PInteger. Тогда p^ будет распознано компилятором именно как переменная типа integer.

Если мы предварительно инициализировали указатель p адресом переменной i, написав p := @i, то после этого мы можем к i обращаться как i и как p^.

С ним (с p^) можно делать любые операции, которые возможны с integer’ом. При этом сам указатель p не меняется, меняются данные в переменной, на которую он указывает, то есть в переменной i.

Кроме этого значок ^ может использоваться в описании типа указателей в секции ‘type’, вот несколько строк из модуля system.pas:


type
PAnsiString = ^AnsiString;
end;

Здесь описывается тип PAnsiString. Тип PAnsiString описывается, как указатель на AnsiString. Именно этой строкой компилятору дают понять, что все типизированные указатели типа PAnsiString могут указывать только на переменные типа AnsiString. Это позволяет компилятору проверят верность передачи параметров в процедуры и верность работы с разыменованными указателями.

Операции сложения/вычитания с указателями.

Так как, собственно, указатели - это самые обычные 32-х разрядные числа, ничто не мешает их складывать и вычитать. В компиляторе Делфи, однако, есть ограничение - такие операции возможны только с указателями типа PChar.

Например, с указателем p: pchar можно написать p := p + 10;
Что при этом произойдет. Допустим, указатели изначально указывал на ячейку 54564786. После команды p := p + 10; он будет указывать на ячейку 54564796. Вполне вероятно, что в этой ячейке может содержаться 11-й символ массива символов s. Так же вероятно (в случае, если размер s меньше 11-ти), что в этой ячейке будет либо мусор, либо уже другая переменная, либо эту ячейку вообще нельзя читать и/или писать. Тогда, в лучшем случае можно получить т.н. AV - acess violation, в худшем - этот же AV рано или поздно появится у заказчика, который работает на другом конце Земли. Поэтому в случае применения операций сложения/вычитания с указателями желательно каким-то образом следить за границами массивов.

Inc(p) инкрементирует указатель. То есть добавляет к нему единицу, ‘продвигая’ его на SizeOf(Type) ячеек вверх. Инкремент (Inc) и декремент (Dec) возможен с любыми типизированными указателями.

Указатели в Delphi. Часть первая.

20.04.2009

Примем платформу - Intel + Windows. Считаем, что указатель 32 бита, память - линейна и непрерывна, её 4 гигабайта. Как менеджер памяти винды и делфи это разруливают, что бы оно почти так было в реальном приложении - это их проблемы. За это им уплачено.
Тогда всё просто. Есть т.н. ячейки памяти. Их, соответственно, 4 с немногим миллиарда. Они пронумерованы с нулевой по 4-х миллиардную. Все ячейки - 8-ми битные (1 байт).
Допустим, есть 32-х битная переменная i, первый байт из четырёх которой лежит в ячейке (по адресу) номер 54564786.
Допустим, также есть некоторая переменная p типа pointer. Она - 32-х битная, то есть занимает 4 байта. И лежит где-то в этой же памяти.
Так вот, если в переменную p записать число 54564786, это и будет указатель на переменную i. Затем, ‘получив’ число 54564786 из переменной p можно добраться до переменной i, ‘взяв’ данные по адресу 54564786 - операция называется ‘разыменовывание указателя’.

Nil.

Изначально в инициализированных переменных содержаться нули. Если в переменную p до того, как из неё будут читать, ничего не писали, то говорят, что указатель не инициализирован. Т.е. указывает ‘в никуда’, хотя на самом деле указывает на 0-ю ячейку). Если попробовать разыменовать указатель, который указывает на ячейку номер 0, это приведет к исключению.

Как это работает.

Была создана специальная область памяти - ловушка (64 кб), находящаяся в самом начале адресного пространства. Т.е. от ячейки номер 0 и выше. Создана, что бы ловить ошибки при работе с неинициализированными или неверно инициализированными указателями. При попытке доступа в эту область происходит исключение.

Виды указателей.

Бывают двух видов - типизированные и нетипизированные. Нетипизированный - это обычный Pointer. Типизированные - все остальные. Например, PChar - указатель на Char. Разницы между ними принципиальной нет. Это те же 4 байта, в которые записан адрес переменной. Только, например, в случае PChar, это может быть не любая переменная, а только переменная типа Char.
Реализуется это на уровне компилятора. После того, как компилятор собрал проект в экзешник, информация о том, что p - это был указатель на Byte, или на Char, или на Integer, нигде не сохраняется.

Естественно, в памяти переменную типа Char от переменной типа Byte отличить невозможно. Соответственно, указатели PByte и PChar (как и любые другие) в памяти - это совершенно одинаковые и ничем не выдающиеся переменные.