2016-06-23 4 views
1

누군가가 올바른 방향으로 나를 가리킬 수 있는지 궁금 해서요. 이미지에서 텍스트를 더 쉽게 읽을 수 있도록 자바 스크립트를 사용하여 전화 카메라에서 가져온 이미지의 밝기/대비를 자동 조정합니다.밝기/대비를 자동 조정하여 이미지에서 텍스트를 읽습니다.

감사의 말 :

감사합니다.

+0

캔버스와 비트 맵 조작. 영구적 일 필요가 없다면 CSS 필터를 적용 할 수 있습니다 (물론 CSS는 자동 조정을 허용하지 않습니다). 자동 조정을 위해 캔버스 + 히스토그램이 필요합니다. – K3N

+1

글쎄, "자동 조정"을 원한다면 현재 이미지 상태를 평가하고 밝기/대비를 어둡게하거나 증가시키는 많은 코드를 작성해야합니다. 사용자의 취향에 따라 밝기와 대비를위한 슬라이더 조정 기능이있는 JS 응용 프로그램을 만드는 것이 더 쉽습니다. 그게 당신의 목표가 아닐 수도 있습니다. 자동 버전의 경우 코드가 @ K3N이 답변에서 제안한 것을 수행하는지 확인하십시오 ... –

답변

4

이미지를 자동으로 조정하려면 이미지에서 생성 한 막대 그래프를 사용하고 임계 값을 사용하여 픽셀 값을 반대쪽 끝의 최대 값으로 조정하는 데 사용할 흑백 포인트를 찾습니다.

HTML5에서 픽셀 정보를 읽으려면 canvas 요소를 사용해야합니다. 히스토그램

에게 히스토그램을 구축

값이 가장 화상으로 표시되는 개요이다. 밝기 대비를 위해 우리는 luma 값 (픽셀의 밝기)에 관심이 있습니다.

example histogram
예 루마 히스토그램

산출하는 휘도 값은 우리 REC.709 (여기서 사용 AKA 추천 BT.709,) 또는 REC.601 수식을 사용할 수있다.

Y = 0.299 * R + 0.587 * G + 0.114 * B 

우리는 달리 우리 수납 정수 값을 [0, 255] (아래 예 코드 참조)에 기초하여 상기 히스토그램을 구축 힘든 시간을받는 것, 정수 (iluma = Math.round(luma);)이 변환 할 필요가있다.

사용할 범위를 결정하는 전략은 다양 할 수 있지만 간단히하기 위해 양 끝의 최소 픽셀 표현을 기반으로 임계 값 전략을 선택할 수 있습니다.

histogram threshold
레드 라인을 보여주는 예 임계 값

우리가 왼쪽에서 오른쪽으로 스캔 할 임계 값을 기반으로 어두운을 찾으려면 우리가 임계 사용과 같은 최소값 위의 루마 값을 얻을 때. 우리가 중심에 도달하면 (또는 33 % 만) 0과 기본값을 맞출 수 있습니다.

가장 밝은 값은 오른쪽에서 왼쪽으로 255를 기본값으로 사용합니다. 임계 값이없는 경우 기본값으로 255로 설정됩니다.

물론 각 끝마다 서로 다른 임계 값을 사용할 수 있습니다. 시나리오에 맞는 것을 찾을 때까지 모든 값의 시행 착오입니다.

이제 우리는 최소 - 최대 범위를 나타내는 두 개의 값을 가져야한다 : 임계치에 기초

min-max range
최소 - 최대 범위를 일반적인 휘도 레벨

먼저 스케일을 계산하는 스케일링

우리가 min-max 범위를 기반으로 사용해야하는 요인 :

scale = 255/(max - min) * 2 

클립을 의미하는 경우에도 각 구성 요소에서 분을 뺍니다 (< 0이 값을 0으로 설정 한 경우). 뺄 때 우리는 축척 계수를 사용하여 각 구성 요소 값을 축척합니다. 끝의 x2는 루마와 실제 RGB 값 사이의 차이를 보정하는 것입니다. 다른 사람들처럼이 값으로 놀아 라.

우리는 각 화소의 각 성분 (0 클립 스케일)이 작업을 수행 화상 데이터가 소정의 임계 값에 기초하여 최대되어야 콘트라스트를 다시 넣어

component = max(0, component - min) * scale 

.

당신은 히스토그램을 분석하기 위해 전체 이미지 비트 맵을 사용할 필요가 없습니다. 큰 이미지 소스를 다루는 경우 작은 표현으로 축소 할 수 있습니다. 가장 밝거나 가장 어두운 영역 다음에 단일 픽셀이 아닌만큼 많이 필요하지는 않습니다.

넌 밝게 및 multiply, lighten으로 자기 블렌딩 모드를 이용하여 명암 화상을 추가/soft-lighthard-light 등 (< = IE11 블렌딩 모드를 지원하지 않음). 이 수식을 조정하고 실험하십시오.

이것은 위에서 설명한 기술을 보여주는 버퍼에서 작동합니다. 더 복잡하고 정확한 방법이 있지만 이것은 개념 증명 (CC-3.0-by-sa, attribution required으로 라이센스)으로 주어집니다.

10 %의 임계 값부터 시작합니다. 임계 값을 사용하여 결과의 ​​차이를 보려면 슬라이더를 사용하십시오. 임계 값은 여기에 표시된 것 이외의 다른 방법을 통해 계산 될 수 있습니다. 실험! 전체 페이지를 사용하여

실행 조각 -

var ctx = c.getContext("2d"), 
 
    img = new Image; // some demo image 
 

 
img.crossOrigin =""; // needed for demo 
 
img.onload = setup; 
 
img.src = "//i.imgur.com/VtNwHbU.jpg"; 
 

 
function setup() { 
 
    // set canvas size based on image 
 
    c.width = this.width; 
 
    c.height = this.height; 
 
\t 
 
    // draw in image to canvas 
 
    ctx.drawImage(this, 0, 0); 
 

 
    // keep the original for comparsion and for demo 
 
    org.src = c.toDataURL(); 
 

 
    process(this, +tv.value); 
 
} 
 

 
function process(img, thold) { //thold = % of hist max 
 

 
    var width = img.width, height = img.height, 
 
     idata, data, 
 
     i, min = -1, max = -1,    // to find min-max 
 
     maxH = 0,       // to find scale of histogram 
 
     scale, 
 
     hgram = new Uint32Array(width); // histogram buffer (or use Float32) 
 
\t 
 
    // get image data 
 
    idata = ctx.getImageData(0, 0, img.width, img.height); // needed for later 
 
    data = idata.data; // the bitmap itself 
 
\t 
 
    // get lumas and build histogram 
 
    for(i = 0; i < data.length; i += 4) { 
 
    var luma = Math.round(rgb2luma(data, i)); 
 
    hgram[luma]++; // add to the luma bar (and why we need an integer) 
 
    } 
 
\t 
 
    // find tallest bar so we can use that to scale threshold 
 
    for(i = 0; i < width; i++) { 
 
    if (hgram[i] > maxH) maxH = hgram[i]; 
 
    } 
 

 
    // use that for threshold 
 
    thold *= maxH; 
 
\t 
 
    // find min value 
 
    for(i = 0; i < width * 0.5; i++) { 
 
    if (hgram[i] > thold) { 
 
     min = i; 
 
     break; 
 
    } 
 
    } 
 
    if (min < 0) min = 0;    // not found, set to default 0 
 

 
    // find max value 
 
    for(i = width - 1; i > width * 0.5; i--) { 
 
    if (hgram[i] > thold) { 
 
     max = i; 
 
     break; 
 
    } 
 
    } 
 
    if (max < 0) max = 255;   // not found, set to default 255 
 

 
    scale = 255/(max - min) * 2; // x2 compensates (play with value) 
 
    out.innerHTML = "Min: " + min + " Max: " + max + 
 
    " Scale: " + scale.toFixed(1) + "x"; 
 
\t 
 
    // scale all pixels 
 
    for(i = 0; i < data.length; i += 4) { 
 
    data[i ] = Math.max(0, data[i] - min) * scale; 
 
    data[i+1] = Math.max(0, data[i+1] - min) * scale; 
 
    data[i+2] = Math.max(0, data[i+2] - min) * scale; 
 
    } 
 
\t 
 
    ctx.putImageData(idata, 0, 0) 
 
} 
 

 
tv.oninput = function() { 
 
    v.innerHTML = (tv.value * 100).toFixed(0) + "%"; 
 
    ctx.drawImage(img, 0, 0); 
 
    process(img, +tv.value) 
 
}; 
 

 
function rgb2luma(px, pos) { 
 
    return px[pos] * 0.299 + px[pos+1] * 0.587 + px[pos+2] * 0.114 
 
}
<label>Threshold: 
 
<input id=tv type=range min=0 max=1 step= 0.01 value=0.1></label> 
 
<span id=v>10%</span><br> 
 
<canvas id=c></canvas><br> 
 
<div id=out></div> 
 
<h3>Original:</h3> 
 
<img id=org>

+0

완벽 ... 고마워요 ... 미안 해요. 내 일이 다른 우선 순위 때문에 일시 중지되었으므로 올 수 없었습니다. 다시 이전에 .... –

관련 문제