中国白 發表於 2019-5-29 15:08:00

Android开发 Camera2开发_2_预览分辨率或拍照分辨率的计算

<h1><span style="color: rgba(22, 145, 121, 1)">版权声明</span></h1>
<p>本文来自博客园,作者:观心静&nbsp;,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/10943966.html</p>
<div>本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。</div>
<h1><span style="color: rgba(22, 145, 121, 1)">前言</span></h1>
<p>  不管在Camera1或者Camera2在适配不同手机/不同使用场景的情况下都需要计算摄像头里提供的分辨率列表中最合适的那一个分辨率.所以在需要大量机型适配的app,是不建议不经过计算直接自定义分辨率设置到预览或者拍照照片中,有概率会因为摄像头不支持你输入的自定义分辨率导致报错或者打不开摄像头.</p>
<p>  如果你的确有需求要自定义分辨率,那么使用场景只有一个那就是你是在开发Android设备,并且你输入的自定义分辨率确定在这个设备上不会报错.</p>
<p>  目前本人总结的2个分辨率计算方法有2个:</p>
<ul>
<li><span style="color: rgba(0, 128, 128, 1)">  求最佳比例正方形分辨率</span></li>
<li><span style="color: rgba(0, 128, 128, 1)">  求最满足宽度的情况下,在找到最接近高度的分辨率.</span></li>
</ul>
<p>  下面我就来解释这个2个计算方法.</p>
<h1><span style="color: rgba(0, 128, 128, 1)">求最佳比例正方形分辨率</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">  较为歪门邪道的方法,核心就是TextureView的宽高比与摄像头的高宽比做差值比较,注意这里一个是宽高一个是高宽,求出来的结果就是在指定指定比例最接近正方形的分辨率</span></p>
<p>  优点:因为是正方形的分辨率,所以在预览的时候不管是什么尺寸的TextureView的都能显示的不会变形.所以比较适合在小尺寸TextureView上</p>
<p>  缺点:在预览的时候其实无法完全显示完整(正方形不管怎么样都有可能上下或者左右超出View的大小),所以TextureView会自动忽略四周部分,只显示最中间的部分.这样拍照的时候就会发现预览与实际照片显示范围不一致.</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">  /**</span><span style="color: rgba(0, 128, 0, 1)">
   * 获取匹配的大小 这里是Camera2获取分辨率数组的方式,Camera1获取不同,计算一样
   * </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
   <span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Size getMatchingSize(){
            Size selectSize </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">float</span> selectProportion = 0<span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            </span><span style="color: rgba(0, 0, 255, 1)">float</span> viewProportion = (<span style="color: rgba(0, 0, 255, 1)">float</span>)mTextureView.getWidth() / (<span style="color: rgba(0, 0, 255, 1)">float</span>)mTextureView.getHeight();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">计算View的宽高比</span>
            CameraCharacteristics cameraCharacteristics =<span style="color: rgba(0, 0, 0, 1)"> mCameraManager.getCameraCharacteristics(mCurrentCameraId);
            StreamConfigurationMap streamConfigurationMap </span>=<span style="color: rgba(0, 0, 0, 1)"> cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Size[] sizes </span>=<span style="color: rgba(0, 0, 0, 1)"> streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; sizes.length; i++<span style="color: rgba(0, 0, 0, 1)">){
                Size itemSize </span>=<span style="color: rgba(0, 0, 0, 1)"> sizes;
                </span><span style="color: rgba(0, 0, 255, 1)">float</span> itemSizeProportion = (<span style="color: rgba(0, 0, 255, 1)">float</span>)itemSize.getHeight() / (<span style="color: rgba(0, 0, 255, 1)">float</span>)itemSize.getWidth();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">计算当前分辨率的高宽比</span>
                <span style="color: rgba(0, 0, 255, 1)">float</span> differenceProportion = Math.abs(viewProportion - itemSizeProportion);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">求绝对值</span>
                Log.e(TAG, "相减差值比例="+<span style="color: rgba(0, 0, 0, 1)">differenceProportion );
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (i == 0<span style="color: rgba(0, 0, 0, 1)">){
                  selectSize </span>=<span style="color: rgba(0, 0, 0, 1)"> itemSize;
                  selectProportion </span>=<span style="color: rgba(0, 0, 0, 1)"> differenceProportion;
                  </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
                }
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (differenceProportion &lt;= selectProportion){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断差值是不是比之前的选择的差值更小</span>
                  <span style="color: rgba(0, 0, 255, 1)">if</span> (differenceProportion == selectProportion){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果差值与之前选择的差值一样</span>
                        <span style="color: rgba(0, 0, 255, 1)">if</span> (selectSize.getWidth() + selectSize.getHeight() &lt; itemSize.getWidth() + itemSize.getHeight()){<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">选择分辨率更大的Size</span>
                            selectSize =<span style="color: rgba(0, 0, 0, 1)"> itemSize;
                            selectProportion </span>=<span style="color: rgba(0, 0, 0, 1)"> differenceProportion;
                        }

                  }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                        selectSize </span>=<span style="color: rgba(0, 0, 0, 1)"> itemSize;
                        selectProportion </span>=<span style="color: rgba(0, 0, 0, 1)"> differenceProportion;
                  }
                }
            }

      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (CameraAccessException e) {
            e.printStackTrace();
      }
      Log.e(TAG, </span>"getMatchingSize: 选择的比例是="+<span style="color: rgba(0, 0, 0, 1)">selectProportion);
      Log.e(TAG, </span>"getMatchingSize: 选择的尺寸是 宽度="+selectSize.getWidth()+"高度="+<span style="color: rgba(0, 0, 0, 1)">selectSize.getHeight());
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> selectSize;
    }</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">求最满足宽度的情况下,在找到最接近高度的分辨率</span></h1>
<p>  这个是最正常的算法了,<span style="color: rgba(0, 0, 0, 1)">核心就是</span>找到与屏幕宽度最接近的分辨率,然后在找最接近屏幕高度的分辨率.这里是屏幕宽度是最高优先级的,其次在满足高度.</p>
<p>  优点:预览图像与拍照照片的效果完全一致.</p>
<p>  缺点:</p>
<ol>
<li>  只能满足全屏幕预览的拍照情况下,各种奇葩自定义<span style="color: rgba(0, 0, 0, 1)">大小的<span style="color: rgba(0, 0, 0, 1)">TextureView</span>你基本上不可能找到满足的宽度的分辨率.</span></li>
<li><span style="color: rgba(0, 0, 0, 1)">  因为需要让<span style="color: rgba(0, 0, 0, 1)">TextureView的高度跟随分辨率高度,所以</span>预览的上面或者下面可能会有需要留出空白区域的情况.(可以用黑色背景View填充),全屏预览的时候可以忽略这个情况,因为基本上手机的摄像头都会有一个分辨率刚好与屏幕分辨率一致.但是不排除个别奇葩手机</span></li>
</ol>
<p> <span style="color: rgba(255, 0, 0, 1)"><strong> 在看代码前这里说明一个重要知识!摄像头分辨率的宽度和高度与屏幕分辨率的宽度和高度的对应</strong></span></p>
<p><span style="color: rgba(255, 0, 0, 1)">  <span style="color: rgba(0, 0, 0, 1)">1.摄像头分辨率的宽度和高度其实是手机横屏下的才是正确方向.如下图所示</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  <img src="https://img2018.cnblogs.com/blog/1497956/201905/1497956-20190529143041447-280701443.png" alt=""></span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  2.屏幕的分辨率的宽度和高度依然是手机竖屏下的高度和宽度.</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">  <img src="https://img2018.cnblogs.com/blog/1497956/201905/1497956-20190529143706930-1127450914.png" alt=""></span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">代码部分</span></span></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Size getMatchingSize2(){
      Size selectSize </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            CameraCharacteristics cameraCharacteristics </span>=<span style="color: rgba(0, 0, 0, 1)"> mCameraManager.getCameraCharacteristics(mCurrentCameraId);
            StreamConfigurationMap streamConfigurationMap </span>=<span style="color: rgba(0, 0, 0, 1)"> cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Size[] sizes </span>=<span style="color: rgba(0, 0, 0, 1)"> streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
            DisplayMetrics displayMetrics </span>= getResources().getDisplayMetrics(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">因为我这里是将预览铺满屏幕,所以直接获取屏幕分辨率</span>
            <span style="color: rgba(0, 0, 255, 1)">int</span> deviceWidth = displayMetrics.widthPixels; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">屏幕分辨率宽</span>
            <span style="color: rgba(0, 0, 255, 1)">int</span> deviceHeigh = displayMetrics.heightPixels; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">屏幕分辨率高</span>
            Log.e(TAG, "getMatchingSize2: 屏幕密度宽度="+<span style="color: rgba(0, 0, 0, 1)">deviceWidth);
            Log.e(TAG, </span>"getMatchingSize2: 屏幕密度高度="+<span style="color: rgba(0, 0, 0, 1)">deviceHeigh );
            </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
             * 循环40次,让宽度范围从最小逐步增加,找到最符合屏幕宽度的分辨率,
             * 你要是不放心那就增加循环,肯定会找到一个分辨率,不会出现此方法返回一个null的Size的情况
             * ,但是循环越大后获取的分辨率就越不匹配
             </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
            <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> j = 1; j &lt; 41; j++<span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; sizes.length; i++) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">遍历所有Size</span>
                  Size itemSize =<span style="color: rgba(0, 0, 0, 1)"> sizes;
                  Log.e(TAG,</span>"当前itemSize 宽="+itemSize.getWidth()+"高="+<span style="color: rgba(0, 0, 0, 1)">itemSize.getHeight());
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断当前Size高度小于屏幕宽度+j*5&amp;&amp;判断当前Size高度大于屏幕宽度-j*5</span>
                  <span style="color: rgba(0, 0, 255, 1)">if</span> (itemSize.getHeight() &lt; (deviceWidth + j*5) &amp;&amp; itemSize.getHeight() &gt; (deviceWidth - j*5<span style="color: rgba(0, 0, 0, 1)">)) {
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (selectSize != <span style="color: rgba(0, 0, 255, 1)">null</span>){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果之前已经找到一个匹配的宽度</span>
                            <span style="color: rgba(0, 0, 255, 1)">if</span> (Math.abs(deviceHeigh-itemSize.getWidth()) &lt; Math.abs(deviceHeigh - selectSize.getWidth())){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">求绝对值算出最接近设备高度的尺寸</span>
                              selectSize =<span style="color: rgba(0, 0, 0, 1)"> itemSize;
                              </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
                            }
                        }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                            selectSize </span>=<span style="color: rgba(0, 0, 0, 1)"> itemSize;
                        }

                  }
                }
                </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
               * 因为需要满足宽度,所以原则上如果没有必要,首次找到最接近宽度屏幕的摄像头高度后就跳出循环
               </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
                <span style="color: rgba(0, 0, 255, 1)">if</span>(selectSize != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){<br>            <span style="color: rgba(0, 0, 0, 1)"> Log.e(TAG, "getMatchingSize2: 选择的分辨率宽度="+<span style="color: rgba(0, 0, 0, 1)">selectSize.getWidth()); <br>             Log.e(TAG, "getMatchingSize2: 选择的分辨率高度="+<span style="color: rgba(0, 0, 0, 1)">selectSize.getHeight());</span></span></span>
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> selectSize;
                }
            }
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (CameraAccessException e) {
            e.printStackTrace();
      }
      Log.e(TAG, </span>"getMatchingSize2: 选择的分辨率宽度="+<span style="color: rgba(0, 0, 0, 1)">selectSize.getWidth());
      Log.e(TAG, </span>"getMatchingSize2: 选择的分辨率高度="+<span style="color: rgba(0, 0, 0, 1)">selectSize.getHeight());
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> selectSize;
    }</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">&nbsp;</span></span></p>

</div>
<div id="MySignature" role="contentinfo">
    <div style="text-align: center">
    <p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/10943966.html </p>
    <div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/10943966.html
頁: [1]
查看完整版本: Android开发 Camera2开发_2_预览分辨率或拍照分辨率的计算