Skip to content

Instantly share code, notes, and snippets.

@aanoaa
Created June 14, 2013 05:50
Show Gist options
  • Save aanoaa/5779743 to your computer and use it in GitHub Desktop.
Save aanoaa/5779743 to your computer and use it in GitHub Desktop.
$ cpanm Image::ExifTool

제 경우에는 문제없이 설치 되었습니다.

#!/usr/bin/env perl
use strict;
use warnings;
use Image::ExifTool;

my $exifTool = new Image::ExifTool;
$exifTool->ExtractInfo('a.jpg');
print "Software: ", $exifTool->GetValue('Software'), "\n";

$exifTool->SetNewValue( 'Software', 'Image::ExitTool' );
if ( $exifTool->WriteInfo( 'a.jpg', 'b.jpg' ) ) {
    print "success for WriteInfo\n";
    $exifTool->ExtractInfo('b.jpg');
    print "Software: ", $exifTool->GetValue('Software'), "\n";
}
~/Desktop $ ls -l *.jpg
-rw-r--r--   1 hshong         hshong      87482  7월 23  2008 a.jpg
-rw-r--r--   1 hshong         hshong      87468  6월 14 14:28 b.jpg

WriteInfo 를 사용했을 때 바뀐 메타데이터 입니다.

BlueTRC
FileAccessDate
FileInodeChangeDate
FileModifyDate
FileName    <- 제가 바꾼거
GreenTRC
RedTRC
Software    <- 제가 바꾼거

Image::ExifTool 에서는 MIME type 이 application/dicomDICOMwrite 기능이 지원되지 않습니다. 문서에도 그렇고 테스트 결과도 그렇습니다. 다른 write 가 지원되는 포맷과 어떻게 다른지 탐구생활 해보도록 하겠습니다.

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

http://www.bic.mni.mcgill.ca/~jharlap/dicom/

dicom header 를 edit 하고 다른 파일로 write 할 수 있는 새로운 library 발견

This library provides the methods to read and parse a DICOM file, then
to recover the contents of each header element by their standard DICOM
group and element codes. Header element values can be edited (either
through the GUI or command line) and the modified file written back to
disk.

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

테스트 해봤는데, DICOM 모듈로 수정한 dcm 파일을 DICOM 모듈에선 읽을 수 있지만, Image::Exif::DICOM 에선 못읽습니다.

PatientID123456 에서 654321 로 수정했을때 4byte 작습니다.

Image::ExifTool 이 더 신뢰가 가기 때문에 DICOM 의 버그일 수 있습니다.
하지만 DICOM 포맷의 헤더 구성등은 DICOM 에 더 자세하게 나와 있습니다.

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

  # Assume that this is explicit VR if b0 and b1 match a known VR code.
  # Possibility (prob 26/16384) exists that the two low order field length 
  # bytes of an implicit VR field will match a VR code.

  # DICOM PS 3.5 Sect 7.1.2: Data Element Structure with Explicit VR
  # Explicit VRs store VR as text chars in 2 bytes.
  # VRs of OB, OW, SQ, UN, UT have VR chars, then 0x0000, then 32 bit VL:
  #
  # +-----------------------------------------------------------+
  # |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 |
  # +----+----+----+----+----+----+----+----+----+----+----+----+
  # |<Group-->|<Element>|<VR----->|<0x0000->|<Length----------->|<Value->
  #
  # Other Explicit VRs have VR chars, then 16 bit VL:
  #
  # +---------------------------------------+
  # |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |
  # +----+----+----+----+----+----+----+----+
  # |<Group-->|<Element>|<VR----->|<Length->|<Value->
  #
  # Implicit VRs have no VR field, then 32 bit VL:
  #
  # +---------------------------------------+
  # |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |
  # +----+----+----+----+----+----+----+----+
  # |<Group-->|<Element>|<Length----------->|<Value->

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

다음은 Image::ExifTool 에서 가져온 내용으로써 DICOM 파일의 byte sequence 의 간단한 검증 regex 입니다.

# quick "magic number" file test used to avoid loading module unnecessarily:
# - regular expression evaluated on first 1024 bytes of file
# - must match beginning at first byte in file
# - this test must not be more stringent than module logic
DICM => '(.{128}DICM|\0[\x02\x04\x06\x08]\0[\0-\x20]|[\x02\x04\x06\x08]\0[\0-\x20]\0)',

위 3개의 rule 이 어디서 나온건지 찾아야 합니다.
문서가 많아서 아직 못찾았습니다.

DICOM PS 3.5 Sect 7.1.2
DICOM Standard PS 3.5 Sect 6.2

위는 소스코드(DICOM) 에 언급된 DICOM 표준안 문서 섹션 번호 입니다.

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

파일을 구성하는 object 의 구조에 대해선
PS 3.5: Data Structure and Encoding#Section 7
에 자세하게 나와있습니다. 요약하면,

파일(dcm 파일)의 구조 표현을 'Data Set' 이라고 한다면, 'Data Set'은 'Data
Element'의 집합으로 구성되어 있습니다.

                -----------------------------------------------
DataSet     => | DataElement | DataElement | ... | DataElement |
                -----------------------------------------------

                ---------------------------------------
DataElement => | TAG | VR | Value Length | Value Field |
                ---------------------------------------
or
                ----------------------------------
DataElement => | TAG | Value Length | Value Field |
                ----------------------------------

TAG         => Group Number(2bytes) + Element Number(2bytes)
VR          => AE|AS|AT|CS|DA|DS|DT|FL|FD|IS|LO|LT|OB|OW|PN|SH|SL|SQ|SS|ST|TM|UI|UL|UN|US|UT
ValueLength => 4bytes or 2bytes
ValueField  => encoded data

명시적인 VR 을 사용하는지와 어떤 VR 을 사용하느냐에 따라 Data Element
의 구조가 달라질 수 있습니다. (그래서 3개)

  • VR 을 사용하면서 OB|OW|OF|SQ|UT|UN 인 것
  • VR 을 사용하면서 위에 것이 아닌 것
  • VR 을 사용않는 것

그런데

DICM => '(.{128}DICM|\0[\x02\x04\x06\x08]\0[\0-\x20]|[\x02\x04\x06\x08]\0[\0-\x20]\0)',

에서 qr/.{128}DICM/ 에 대한 내용은 찾을 수 없었습니다.

Standard Data Element 의 Group Number 는 0x00|0x02|0x04|0x06 를 사용한다는 설명은 있습니다.

Standard Data Elements have an even Group Number that is
not (0000,eeee), (0002,eeee), (0004,eeee), or (0006,eeee).

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

두개의 파일의 다른점은 128 byte 뒤 4byte 가 D I C M0 0 0 0 로 달랐습니다.
위 코멘트와도 연관이 있는 것이, 아무거나 128바이트오고 그뒤에 DICM 의 조건으로 dicom 포맷의 유효성을 판단하기 때문입니다.

어떤 조건인지는 모르겠지만 DICOM.pmDICM 을 넣는 부분을 추가하고 테스트 했더니 성공했습니다만 새로운 버그를 발견했습니다.

Metadata 의 length 가 6자리 였으면 6자리로 밖에 안바뀝니다.(123456 => abcdefg 로 바꿨을때, abcdef 로 변경)
바뀐 content-value 에 따라 length, content-value 를 파일을 재구성 해서 만들어야 하지만 그런 처리가 안되고 단순히 content-value 를 치환 하는것이 아닌가 생각됩니다.

@aanoaa
Copy link
Author

aanoaa commented Jun 14, 2013

지금은 변경된 데이터를 고정된 header 의 Value-Length 만큼 자르고 대입합니다. 즉 헤더길이에 몸을 맞춥니다.
이렇게 하면 편리합니다.

VR(Value Representation) 는 고정인 것과 가변인 것이 있는데, 가변에 대한 계산을 고려하지 않아도 되기 때문입니다.
이를 지원하려면 가변인 VR 일때에 spec 에 정의된 MAX 값을 넘지 않는 범위내에서 Value-Field 를 설정하고 DataElement 의 Value-Length 를 다시 써주면 됩니다.

근데 또 조심해야 될것이 VR 에 따라 ByteSwap 이 이루어지는 것들이 있습니다.

@aanoaa
Copy link
Author

aanoaa commented Jun 16, 2013

위에 두개 사용하니까 잘됩니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment