Imatest IT와 Python을 활용한 CPIQ 분석 자동화

Imatest IT 의 Python 인터페이스는 Imatest 테스트를 간단하게 실행할 수 있는 방법을 제공합니다. 이 글에서는 Imatest 실행을 자동화하고, 테스트 결과를 수집하여 손쉽게 처리하는 방법을 보여드리겠습니다. 예시로, 세 가지 조도 수준에서 다섯 가지 Imatest 모듈을 실행하고, CPIQ 품질 손실 지표를 추출해 보겠습니다.

개발 환경 설정

이미지 모음

각 장치에 대해 다양한 조도 수준에서 여러 테스트 차트의 이미지를 다음과 같이 촬영합니다. (참고: 자세한 내용은 2017년 3월 표준 발간 시 제공될 예정입니다.)

모든 테스트 실행 중

"DeviceX"라는 폴더에 이러한 이미지들을 수집한 후, 조명 조건을 정의하고, Imatest IT 라이브러리를 초기화한 다음, 이 장치와 다른 여러 장치에서 처리 함수를 실행합니다.

led5k = "5000KLED_1000lux"               # Light Levels
tl84 = "TL84_100lux"
tung = "Tung_10lux"
light_conditions = [led5k, tl84, tung]
imatest = ImatestLibrary()
phones = ['DeviceX',                     # Just for example...
          'DeviceY',
          'DeviceZ']
for phone in phones:
    calc_phone(phone)
 
imatest.terminate_library()

주요 처리 스크립트는 다섯 개의 모듈을 호출하고, 각 모듈의 데이터 출력을 수집하여 JSON 파일에 저장합니다.

def calc_phone(phone):
    print('Calculating Metrics for '+phone+ ' *****************************')
    uniformity_results = uniformity(phone) # Uniformity
    multitest_results  = multitest(phone) # Multitest
    dotpattern_results = dotpattern(phone) # Dot Pattern
    esfriso_results    = esfriso(phone) # eSFR ISO
    random_results     = random(phone) # Random
 
    # Output data to disk
    file_name = os.path.join(images_dir, phone, phone + '.json')
    with open(file_name, 'w') as outfile:
        full_data = {'multitest'  : multitest_results,
                     'dotpattern' : dotpattern_results,
                     'esfriso' : esfriso_results,
                     'random' : random_results,
                     'uniformity' : uniformity_results}
        json.dump(full_data, outfile, indent=4, separators=(',',': '))
 
    return full_data

지정된 조명 조건마다 Imatest eSFR ISO 모듈을 호출합니다.

# eSFR ISO (ISO 12233:2014) is used to test Visual Noise (VN) 
# and Spatial Frequency Response (SFR)
def esfriso(base):
    global images_dir, ini_file, light_conditions, op_mode
    output = {}
    for light_source in light_conditions:
        print('Testing ' + base + ' eSFR ISO at ' + light_source)
        input_file = os.path.join(images_dir, base, base+'_eSFR_'+light_source+'.jpg')
        if os.path.exists(input_file) != True:
            raise Exception('File ' + input_file + 'not found!')
        print('opening ' + input_file)
        result = imatest.esfriso_json(input_file=input_file, root_dir=root_dir, 
                                      op_mode=op_mode, ini_file=ini_file)
        data = json.loads(result)
        output[light_source] = data['esfrisoResults'];
 
return output

INI 파일 변경 사항이 실행 중에 즉시 적용됩니다.

이 처리 과정에서 가장 어려운 부분은 Multitest 호출에 대한 영역 선택을 수동으로 업데이트하는 것입니다. Multitest는 아직 Colorchecker SG 대상에 대한 자동 영역 감지 기능을 지원하지 않습니다(곧 지원 예정).

이 경우, [sg] roi, nwid_save 및 nht_save 키를 multicharts-rois.json 파일에 저장된 값으로 대체합니다.

{
"DeviceX_SG_5000KLED_1000lux.JPG": "468 417 2122 1578 468 1588 2102 397",
"DeviceX_SG_TL84_100lux.JPG":"482 376 2142 1571 482 1561 2157 376",
"DeviceX_SG_Tung_10lux.JPG":"386 336 2016 1492 401 1497 2021 321",
"width":"2592",
"height":"1936"
}

우리는 이 스크립트를 사용하여 INI 파일을 수정하고 다양한 설정을 동적으로 삽입합니다.

import ConfigParser
 
def get_config(path): # Used make ConfigParser case sensitive
    config = ConfigParser.ConfigParser()
    config.optionxform=str  # make configparser preserve case
    try:
        config.read(os.path.expanduser(path))
        return config
     except Exception, e:
        log.error(e)
 
def setROI(roi,width,height):
    global ini_file
    imatestini = get_config(ini_file)
 
    imatestini.set('ccsg', 'roi', roi)
    imatestini.set('ccsg', 'nwid_save', width)
    imatestini.set('ccsg', 'nht_save', height)
    with open(tempINI, 'w') as outfile:
        imatestini.write(outfile)
    return

Imatest INI 파일은 대소문자를 구분합니다. 따라서 모든 INI 조작 도구가 섹션 및 키의 대소문자를 유지하도록 하십시오.

이러한 함수들은 멀티차트 함수 호출 내부에서 JSON 파일에서 로드된 값을 사용하여 호출됩니다.

roi_overrides = {}
roi_overrides_lower = {}
roi_override_file = os.path.join(images_dir,base,'multicharts-rois.json')
if os.path.exists(roi_override_file):
    with open(roi_override_file,'r') as fh: # read ROI override file
        roi_overrides = json.load(fh)
    for override, rois in roi_overrides.iteritems(): # convert to lowercase
        roi_overrides_lower[override.lower()] = rois
else:
    raise Exception('ROI override file ' + roi_override_file + ' not found.')
 
if image_file.lower() in roi_overrides_lower:
     setROI(roi_overrides_lower[image_file.lower()], roi_overrides['width'], roi_overrides['height'])
     selectedINI = tempINI
else:
     raise Exception('Missing ROI override for ' + image_file)

점수 추출

마지막으로, 핵심성과지표(KPI)를 추출하는데, 이 지표들은 모두 인지적 품질 손실(QL) 단위로, 최소 식별 차이(JND)로 표현됩니다. 이 스크립트는 내용이 길어서 이 게시물에 모두 담기에는 다소 길기 때문에, 관심 있으신 분들은 GitHub에서 소스 코드를 확인해 보세요.

다음은 계산된 지표들의 결과 집합을 JSON 형식으로 나타낸 것입니다.

{ 'DeviceX': 
    { 'CL_QL': { '5000KLED_1000lux': 0.9142,
                 'TL84_100lux': 0.1803,
                 'Tung_10lux': 2.565},
      'CU_QL': 0.07498,
      'LCD_QL': 0,
      'LGD_QL': 0,
      'SFR_QL': { '5000KLED_1000lux': 0.0,
                  'TL84_100lux': 0.1969,
                  'Tung_10lux': 0.3946},
      'TB_QL': { '5000KLED_1000lux': 1.2,
                 'TL84_100lux': 6.25,
                 'Tung_10lux': 9.1},
      'VN_QL': { '5000KLED_1000lux': 1.113,
                 'TL84_100lux': 2.409,
                 'Tung_10lux': 8.531}},
      'Combined_QL': 11.0245
}

IEEE 적합성 평가 프로그램 에서 테스트 절차 및 종합 점수 계산법이 확정되면, 이러한 결과들을 종합하여 간단한 카메라폰 등급 점수를 산출할 것입니다.

이 예제의 전체 파이썬 소스 코드는 GitHub에 게시되어 있습니다.

기존 Imatest Master 라이선스에 이러한 자동화 기능을 추가하려면 Imatest Ultimate 로 업그레이드하세요. 구매 전에 Imatest IT의 30일 무료 평가판을 신청하여 기능이 어떻게 작동하는지 확인해 볼 수도 있습니다.

관련 웨비나