web-dev-qa-db-ja.com

アスペクト比を計算するアルゴリズムは何ですか?

JavaScriptとともに使用して、ウィンドウ全体に収まるように画像をトリミングする予定です。

編集:次のような形式のアスペクト比のみを受け入れるサードパーティのコンポーネントを使用します:4:316:9

71
Nathan

integer:integerのような16:9ソリューションではなく、float:1のような使用可能なアスペクト比1.77778:1ソリューションを探しているのを集めました。

もしそうなら、あなたがする必要があるのは、最大公約数(GCD)を見つけ、それで両方の値を除算することです。 GCDは、両方の数値を均等に分割する最大の数値です。したがって、6と10のGCDは2、44と99のGCDは11です。

たとえば、1024x768モニターのGCDは256です。両方の値を除算すると、4x3または4:3になります。

(再帰的)GCDアルゴリズム:

function gcd (a,b):
    if b == 0:
        return a
    return gcd (b, a mod b)

Cで:

static int gcd (int a, int b) {
    return (b == 0) ? a : gcd (b, a%b);
}

int main(void) {
    printf ("gcd(1024,768) = %d\n",gcd(1024,768));
}

そして、画面サイズを検出し、そこからアスペクト比を計算する1つの方法を示す完全なHTML/Javascriptがあります。これはFF3で機能します。他のブラウザがscreen.widthおよびscreen.heightに対してどのようなサポートを提供しているかはわかりません。

<html><body>
    <script type="text/javascript">
        function gcd (a, b) {
            return (b == 0) ? a : gcd (b, a%b);
        }
        var w = screen.width;
        var h = screen.height;
        var r = gcd (w, h);
        document.write ("<pre>");
        document.write ("Dimensions = ", w, " x ", h, "<br>");
        document.write ("Gcd        = ", r, "<br>");
        document.write ("Aspect     = ", w/r, ":", h/r);
        document.write ("</pre>");
    </script>
</body></html>

それは出力します(私の奇妙なワイドスクリーンモニター上で):

Dimensions = 1680 x 1050
Gcd        = 210
Aspect     = 8:5

私がこれをテストした他のもの:

Dimensions = 1280 x 1024
Gcd        = 256
Aspect     = 5:4

Dimensions = 1152 x 960
Gcd        = 192
Aspect     = 6:5

Dimensions = 1280 x 960
Gcd        = 320
Aspect     = 4:3

Dimensions = 1920 x 1080
Gcd        = 120
Aspect     = 16:9

私はそれが家で最後のものを持っていればよかったのに、いや、それは残念なことに作業機械です。

アスペクト比がグラフィックサイズ変更ツールでサポートされていないことがわかった場合の対処方法は、別の問題です。おそらく、レターボックスの行を追加するのが最善の方法だと思います(ワイドスクリーンの映画を見ているときに古いテレビの上下に表示される行のように)。画像が要件を満たすまで、それらを上/下または側面(どちらかがレターボックスの行数が少なくなる方)に追加します。

考慮したいことの1つは、16:9から5:4に変更された写真の品質です。レターボックスが導入される前の若い頃にテレビで見ていた、信じられないほど背が高くて薄いカウボーイを今でも覚えています。アスペクト比ごとに1つの異なる画像を用意し、実際の画面のサイズに合わせて正しい画像のサイズを変更してから送信することをお勧めします。

177
paxdiablo
aspectRatio = width / height

それがあなたが望んでいるものなら。次に、ターゲット空間のディメンションの1つをそれに掛けて、(比率を維持する)他のディメンションを見つけることができます。

widthT = heightT * aspectRatio
heightT = widthT / aspectRatio
37
Gishu

paxdiabloの答えは素晴らしいですが、特定の方向に多少のピクセルしか持たない一般的な解像度がたくさんあり、最も一般的な除数アプローチは恐ろしい結果をもたらします。

たとえば、gcdアプローチを使用してニース16:9の比率を与える1360x765の適切に動作する解像度を考えてみましょう。 Steamによると、この解像度はユーザーの0.01%のみが使用し、1366x768は18.9%の人が使用します。 gcdアプローチを使用して得られるものを見てみましょう。

1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)

683:384の比率を最も近い16:9の比率に切り上げたいと思います。

python Steamハードウェア調査ページから貼り付けられた数値でテキストファイルを解析し、すべての解像度と最も近い既知の比率、および各比率の有病率(これは私の私がこれを始めたときの目標):

# Contents pasted from store.steampowered.com/hwsurvey, section 'Primary Display Resolution'
Steam_file = './Steam.txt'

# Taken from http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Vector_Video_Standards4.svg/750px-Vector_Video_Standards4.svg.png
accepted_ratios = ['5:4', '4:3', '3:2', '8:5', '5:3', '16:9', '17:9']

#-------------------------------------------------------
def gcd(a, b):
    if b == 0: return a
    return gcd (b, a % b)

#-------------------------------------------------------
class ResData:

    #-------------------------------------------------------
    # Expected format: 1024 x 768 4.37% -0.21% (w x h prevalence% change%)
    def __init__(self, Steam_line):
        tokens = Steam_line.split(' ')
        self.width  = int(tokens[0])
        self.height = int(tokens[2])
        self.prevalence = float(tokens[3].replace('%', ''))

        # This part based on pixdiablo's gcd answer - http://stackoverflow.com/a/1186465/828681
        common = gcd(self.width, self.height)
        self.ratio = str(self.width / common) + ':' + str(self.height / common)
        self.ratio_error = 0

        # Special case: ratio is not well behaved
        if not self.ratio in accepted_ratios:
            lesser_error = 999
            lesser_index = -1
            my_ratio_normalized = float(self.width) / float(self.height)

            # Check how far from each known aspect this resolution is, and take one with the smaller error
            for i in range(len(accepted_ratios)):
                ratio = accepted_ratios[i].split(':')
                w = float(ratio[0])
                h = float(ratio[1])
                known_ratio_normalized = w / h
                distance = abs(my_ratio_normalized - known_ratio_normalized)
                if (distance < lesser_error):
                    lesser_index = i
                    lesser_error = distance
                    self.ratio_error = distance

            self.ratio = accepted_ratios[lesser_index]

    #-------------------------------------------------------
    def __str__(self):
        descr = str(self.width) + 'x' + str(self.height) + ' - ' + self.ratio + ' - ' + str(self.prevalence) + '%'
        if self.ratio_error > 0:
            descr += ' error: %.2f' % (self.ratio_error * 100) + '%'
        return descr

#-------------------------------------------------------
# Returns a list of ResData
def parse_Steam_file(Steam_file):
    result = []
    for line in file(Steam_file):
        result.append(ResData(line))
    return result

#-------------------------------------------------------
ratios_prevalence = {}
data = parse_Steam_file(Steam_file)

print('Known Steam resolutions:')
for res in data:
    print(res)
    acc_prevalence = ratios_prevalence[res.ratio] if (res.ratio in ratios_prevalence) else 0
    ratios_prevalence[res.ratio] = acc_prevalence + res.prevalence

# Hack to fix 8:5, more known as 16:10
ratios_prevalence['16:10'] = ratios_prevalence['8:5']
del ratios_prevalence['8:5']

print('\nSteam screen ratio prevalences:')
sorted_ratios = sorted(ratios_prevalence.items(), key=lambda x: x[1], reverse=True)
for value in sorted_ratios:
    print(value[0] + ' -> ' + str(value[1]) + '%')

好奇心For盛な人のために、これらはSteamユーザーの間での画面比率の普及率です(2012年10月現在)

16:9 -> 58.9%
16:10 -> 24.0%
5:4 -> 9.57%
4:3 -> 6.38%
5:3 -> 0.84%
17:9 -> 0.11%
12
Petrucio

4:3と16:9のどちらが最適かを判断したいと思います。

function getAspectRatio(width, height) {
    var ratio = width / height;
    return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}
11
Chetan Sastry

これは、元々Pythonで記述された アスペクト比計算コード からjavascriptに移植された、調整可能なレベルのあいまいさを備えたJames Fareyの最良の合理的近似アルゴリズムのバージョンです。

このメソッドは、float(width/height)と分数分子/分母の上限を取ります。

以下の例では、50(1.77835051546)を1035x582ではなく16:9(1.77777777778)として扱う必要があるため、345:194の上限を設定しています。他の回答にリストされているプレーンgcdアルゴリズム。

<html>
<body>
<script type="text/javascript">
function aspect_ratio(val, lim) {

    var lower = [0, 1];
    var upper = [1, 0];

    while (true) {
        var mediant = [lower[0] + upper[0], lower[1] + upper[1]];

        if (val * mediant[1] > mediant[0]) {
            if (lim < mediant[1]) {
                return upper;
            }
            lower = mediant;
        } else if (val * mediant[1] == mediant[0]) {
            if (lim >= mediant[1]) {
                return mediant;
            }
            if (lower[1] < upper[1]) {
                return lower;
            }
            return upper;
        } else {
            if (lim < mediant[1]) {
                return lower;
            }
            upper = mediant;
        }
    }
}

document.write (aspect_ratio(800 / 600, 50) +"<br/>");
document.write (aspect_ratio(1035 / 582, 50) + "<br/>");
document.write (aspect_ratio(2560 / 1440, 50) + "<br/>");

    </script>
</body></html>

結果:

 4,3  // (1.33333333333) (800 x 600)
 16,9 // (1.77777777778) (2560.0 x 1440)
 16,9 // (1.77835051546) (1035.0 x 582)
3
ccpizza

あなたがパフォーマンスマニアなら...

真のバイナリGreat Common Divisorアルゴリズムを使用して、長方形の比率を計算する最速の方法(JavaScript)。

(すべての速度とタイミングのテストは他の人によって行われています。ここで1つのベンチマークを確認できます: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest -common-divisor /

はい、これ:

/* the binary Great Common Divisor calculator */
function gcd (u, v) {
    if (u === v) return u;
    if (u === 0) return v;
    if (v === 0) return u;

    if (~u & 1)
        if (v & 1)
            return gcd(u >> 1, v);
        else
            return gcd(u >> 1, v >> 1) << 1;

    if (~v & 1) return gcd(u, v >> 1);

    if (u > v) return gcd((u - v) >> 1, v);

    return gcd((v - u) >> 1, u);
}

/* returns an array with the ratio */
function ratio (w, h) {
        var d = gcd(w,h);
        return [w/d, h/d];
}

/* example */
var r1 = ratio(1600, 900);
var r2 = ratio(1440, 900);
var r3 = ratio(1366, 768);
var r4 = ratio(1280, 1024);
var r5 = ratio(1280, 720);
var r6 = ratio(1024, 768);


/* will output this: 
r1: [16, 9]
r2: [8, 5]
r3: [683, 384]
r4: [5, 4]
r5: [16, 9]
r6: [4, 3]
*/
3
Arthur da Paz

他の回答に基づいて、Pythonで必要な数値を取得する方法を次に示します。

from decimal import Decimal

def gcd(a,b):
    if b == 0:
        return a
    return gcd(b, a%b)

def closest_aspect_ratio(width, height):
    g = gcd(width, height)
    x = Decimal(str(float(width)/float(g)))
    y = Decimal(str(float(height)/float(g)))
    dec = Decimal(str(x/y))
    return dict(x=x, y=y, dec=dec)

>>> closest_aspect_ratio(1024, 768)
{'y': Decimal('3.0'), 
 'x': Decimal('4.0'), 
 'dec': Decimal('1.333333333333333333333333333')}
1
sleepycal

私はこれがあなたが求めていることをやると思う:

webdeveloper.com-小数から小数へ

幅/高さは小数になり、「/」の代わりに「:」で小数に変換され、「比率」が得られます。

1
Tobias Cohen

Pythonのこのアルゴリズム は、その方法の一部を取得します。


ウィンドウのサイズがおかしい場合はどうなるか教えてください。

たぶんあなたが持っているべきものは、すべての許容可能な比率のリストです(サードパーティのコンポーネントに対して)。次に、ウィンドウに最も近い一致を見つけ、リストからその比率を返します。

1
Nosredna

私が気にするのは必ずしもGCDまたは正確な比率である必要はないので、これは私の答えです:345/113のような人間が理解できない奇妙なものを得るからです。

基本的に、許容可能なランドスケープまたはポートレートの比率とその「値」をフロートとして設定します...次に、フロートバージョンの比率をそれぞれと比較し、絶対値の差が最も小さいアイテムに最も近い比率を比較します。そのようにして、ユーザーが16:9にした後、下から10ピクセルを削除しても、16:9としてカウントされます...

accepted_ratios = {
    'landscape': (
        (u'5:4', 1.25),
        (u'4:3', 1.33333333333),
        (u'3:2', 1.5),
        (u'16:10', 1.6),
        (u'5:3', 1.66666666667),
        (u'16:9', 1.77777777778),
        (u'17:9', 1.88888888889),
        (u'21:9', 2.33333333333),
        (u'1:1', 1.0)
    ),
    'portrait': (
        (u'4:5', 0.8),
        (u'3:4', 0.75),
        (u'2:3', 0.66666666667),
        (u'10:16', 0.625),
        (u'3:5', 0.6),
        (u'9:16', 0.5625),
        (u'9:17', 0.5294117647),
        (u'9:21', 0.4285714286),
        (u'1:1', 1.0)
    ),
}


def find_closest_ratio(ratio):
    lowest_diff, best_std = 9999999999, '1:1'
    layout = 'portrait' if ratio < 1.0 else 'landscape'
    for pretty_str, std_ratio in accepted_ratios[layout]:
        diff = abs(std_ratio - ratio)
        if diff < lowest_diff:
            lowest_diff = diff
            best_std = pretty_str
    return best_std


def extract_ratio(width, height):
    try:
        divided = float(width)/float(height)
        if divided == 1.0:
            return '1:1'
        else:
            return find_closest_ratio(divided)
    except TypeError:
        return None
1
Zargold

GCD検索の代替ソリューションとして、一連の標準値を確認することをお勧めします。リストは Wikipedia にあります。

1
mouviciel

ここでビデオについて話していると仮定すると、ソースビデオのピクセルアスペクト比についても考慮する必要があります。例えば。

PAL DVの解像度は720x576です。これは4:3のように見えます。ピクセルアスペクト比(PAR)に応じて、画面比は4:3または16:9になります。

詳細については、こちらをご覧ください http://en.wikipedia.org/wiki/Pixel_aspect_ratio

スクエアピクセルアスペクト比を取得できます。多くのWebビデオがありますが、他のケースには注意してください。

お役に立てれば

マーク

1
Mark Lakewood
Width / Height

0

アスペクト比は幅を高さで割ったものだと思います。

 r = w/h
0

これを行うための奇妙な方法のビットですが、アスペクトとして解像度を使用します。例えば。

1024:768

または試すことができます

var w = screen.width;
var h = screen.height;
for(var i=1,asp=w/h;i<5000;i++){
  if(asp*i % 1==0){
    i=9999;
    document.write(asp*i,":",1*i);
  }
}
0
Aron