整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          記錄我首次在Vue中使用D3.js繪制立體直方圖的經

          記錄我首次在Vue中使用D3.js繪制立體直方圖的經歷

          話不多說直接上代碼

          模板

          源數據格式,小編用得是動態數據就不給大家展示了就放個格式給大家看看吧

          data=[

          {

          letter: "白皮雞蛋",

          child: {

          category: "0",

          value: "459.00"

          }

          },

          {

          letter: "紅皮雞蛋",

          child: {

          category: "0",

          value: "389.00"

          }

          },....]

          接下來是重點啊代碼有點多(前方高能)

          d3在vue中安裝也很簡單 直接 npm install d3

          import * as d3 from "d3";

          我是封裝在chart函數中的(兩個參數分別是源數據和圖像掛載dom在vue中直接用this.$refs.cil其他地方的用法和JQ類似)

          function chart(data, myEle) {

          {

          var margin={

          top: 20,

          right: 50,

          bottom: 50,

          left: 90

          };

          var svgWidth=window.screen.width -margin.right -margin.left; // 檢測屏幕

          var svgHeight=500;

          //創建各個面的顏色數組

          var mainColorList=[

          "#f6e242",

          "#ebec5b",

          "#d2ef5f",

          "#b1d894",

          "#97d5ad",

          "#82d1c0",

          "#70cfd2",

          "#63c8ce",

          "#50bab8",

          "#38a99d"

          ];

          var topColorList=[

          "#e9d748",

          "#d1d252",

          "#c0d75f",

          "#a2d37d",

          "#83d09e",

          "#68ccb6",

          "#5bc8cb",

          "#59c0c6",

          "#3aadab",

          "#2da094"

          ];

          var rightColorList=[

          "#dfce51",

          "#d9db59",

          "#b9d54a",

          "#9ece7c",

          "#8ac69f",

          "#70c3b1",

          "#65c5c8",

          "#57bac0",

          "#42aba9",

          "#2c9b8f"

          ];

          // console.log(this.$refs.cil)

          var svg=d3

          .select(myEle)

          .append("svg")

          .attr("width", svgWidth)

          .attr("height", svgHeight)

          .attr("id", "svg-column");

          // 創建X軸序數比例尺

          function addXAxis() {

          var transform=d3.geoTransform({

          point: function (x, y) {

          this.stream.point(x, y);

          }

          }); //定義幾何路徑

          var path=d3.geoPath().projection(transform);

          var xLinearScale=d3

          .scaleBand()

          .domain(

          data.map(function (d) {

          return d.letter;

          })

          )

          .range([0, svgWidth - margin.right - margin.left], 0.1);

          var xAxis=d3.axisBottom(xLinearScale).ticks(data.length); //繪制X軸

          var xAxisG=svg

          .append("g")

          .call(xAxis)

          .attr(

          "transform",

          "translate(" + margin.left + "," + (svgHeight - margin.bottom) +")"

          ); //刪除原X軸

          xAxisG.select("path").remove();

          xAxisG.selectAll("line").remove(); //繪制新的立體X軸

          xAxisG

          .append("path")

          .datum({

          type: "Polygon",

          coordinates: [

          [

          [20, 0],

          [0, 15],

          [svgWidth - margin.right - margin.left, 15],

          [svgWidth + 20 - margin.right - margin.left, 0],

          [20, 0]

          ]

          ]

          })

          .attr("d", path)

          .attr("fill", "rgb(187,187,187)");

          xAxisG

          .selectAll("text")

          .attr("fill", "#646464")

          .attr("class", 'rotate_txt')

          .attr("transform-origin", "50% top 0")

          .attr("transform", "translate(0,20)");

          dataProcessing(xLinearScale); //核心算法

          }

          var yLinearScale;

          //創建y軸的比例尺渲染y軸

          function addYScale() {

          yLinearScale=d3

          .scaleLinear()

          .domain([

          0,

          d3.max(data, function (d, i) {

          return d.child.value * 1;

          }) * 1.2

          ])

          .range([svgHeight - margin.top - margin.bottom, 0]);

          //定義Y軸比例尺以及刻度

          var yAxis=d3.axisLeft(yLinearScale).ticks(6);

          //繪制Y軸

          var yAxisG=svg

          .append("g")

          .call(yAxis)

          .attr(

          "transform",

          "translate(" + (margin.left + 10) + "," + margin.top + ")"

          );

          yAxisG

          .selectAll("text")

          .attr("font-size", "18px")

          .attr("fill", "#636363");

          //刪除原Y軸路徑和tick

          yAxisG.select("path").remove();

          yAxisG.selectAll("line").remove();

          }

          //核心算法思路是

          function dataProcessing(xLinearScale) {

          var angle=Math.PI / 2.3;

          for (var i=0; i < data.length; i++) {

          var d=data[i];

          var depth=10;

          d.ow=xLinearScale.bandwidth() * 0.7;

          d.ox=xLinearScale(d.letter);

          d.oh=1;

          d.p1={

          x: Math.cos(angle) * d.ow,

          y: -Math.sin(angle) - depth

          };

          d.p2={

          x: d.p1.x + d.ow,

          y: d.p1.y

          };

          d.p3={

          x: d.p2.x,

          y: d.p2.y + d.oh

          };

          }

          }

          //tip的創建方法

          var tipTimerConfig={

          longer: 0,

          target: null,

          exist: false,

          winEvent: window.event,

          boxHeight: 398,

          boxWidth: 376,

          maxWidth: 376,

          maxHeight: 398,

          tooltip: null,

          showTime: 3500,

          hoverTime: 300,

          displayText: "",

          show: function (val, e) {

          "use strict";

          var me=this;

          if (e !=null) {

          me.winEvent=e;

          }

          me.displayText=val;

          me.calculateBoxAndShow();

          me.createTimer();

          },

          calculateBoxAndShow: function () {

          "use strict";

          var me=this;

          var _x=0;

          var _y=0;

          var _w=document.documentElement.scrollWidth;

          var _h=document.documentElement.scrollHeight;

          var wScrollX=window.scrollX || document.body.scrollLeft;

          var wScrollY=window.scrollY || document.body.scrollTop;

          var xMouse=me.winEvent.x + wScrollX;

          if (_w - xMouse < me.boxWidth) {

          _x=xMouse - me.boxWidth - 10;

          } else {

          _x=xMouse;

          }

          var _yMouse=me.winEvent.y + wScrollY;

          if (_h - _yMouse < me.boxHeight + 18) {

          _y=_yMouse - me.boxHeight - 25;

          } else {

          _y=_yMouse + 18;

          }

          me.addTooltip(_x, _y);

          },

          addTooltip: function (page_x, page_y) {

          "use strict";

          var me=this;

          me.tooltip=document.createElement("div");

          me.tooltip.style.left=page_x + "px";

          me.tooltip.style.top=page_y + "px";

          me.tooltip.style.position="absolute";

          me.tooltip.style.width=me.boxWidth + "px";

          me.tooltip.style.height=me.boxHeight + "px";

          me.tooltip.className="three-tooltip";

          var divInnerHeader=me.createInner();

          divInnerHeader.innerHTML=me.displayText;

          me.tooltip.appendChild(divInnerHeader);

          document.body.appendChild(me.tooltip);

          },

          createInner: function () {

          "use strict";

          var me=this;

          var divInnerHeader=document.createElement("div");

          divInnerHeader.style.width=me.boxWidth + "px";

          divInnerHeader.style.height=me.boxHeight + "px";

          return divInnerHeader;

          },

          ClearDiv: function () {

          "use strict";

          var delDiv=document.body.getElementsByClassName("three-tooltip");

          for (var i=delDiv.length - 1; i >=0; i--) {

          document.body.removeChild(delDiv[i]);

          }

          },

          createTimer: function (delTarget) {

          "use strict";

          var me=this;

          var delTip=me.tooltip;

          var delTarget=tipTimerConfig.target;

          var removeTimer=window.setTimeout(function () {

          try {

          if (delTip !=null) {

          document.body.removeChild(delTip);

          if (tipTimerConfig.target==delTarget) {

          me.exist=false;

          }

          }

          clearTimeout(removeTimer);

          } catch (e) {

          clearTimeout(removeTimer);

          }

          }, me.showTime);

          },

          hoverTimerFn: function (showTip, showTarget) {

          "use strict";

          var me=this;

          var showTarget=tipTimerConfig.target;

          var hoverTimer=window.setInterval(function () {

          try {

          if (tipTimerConfig.target !=showTarget) {

          clearInterval(hoverTimer);

          } else if (

          !tipTimerConfig.exist &&

          new Date().getTime() - me.longer > me.hoverTime

          ) {

          //show

          tipTimerConfig.show(showTip);

          tipTimerConfig.exist=true;

          clearInterval(hoverTimer);

          }

          } catch (e) {

          clearInterval(hoverTimer);

          }

          }, tipTimerConfig.hoverTime);

          }

          };

          var createTooltipTableData=function (info) {

          var ary=[];

          ary.push("<div class='tip-hill-div'>");

          ary.push("<p>" + info.letter +' '+ info.child.value + "</p>");

          ary.push("</div>");

          return ary.join("");

          };

          // 核心算法寫完,就到了最終的渲染了

          function addColumn() {

          function clumnMouseover(d) {

          d3.select(this)

          .selectAll(".transparentPath")

          .attr("opacity", 0.8);

          // 添加 div

          tipTimerConfig.target=this;

          tipTimerConfig.longer=new Date().getTime();

          tipTimerConfig.exist=false;

          //獲取坐標

          tipTimerConfig.winEvent={

          x: event.clientX - 100,

          y: event.clientY

          };

          tipTimerConfig.boxHeight=50;

          tipTimerConfig.boxWidth=140;

          //hide

          tipTimerConfig.ClearDiv();

          //show

          tipTimerConfig.hoverTimerFn(createTooltipTableData(d));

          }

          function clumnMouseout(d) {

          d3.select(this)

          .selectAll(".transparentPath")

          .attr("opacity", 1);

          tipTimerConfig.target=null;

          tipTimerConfig.ClearDiv();

          }

          var g=svg

          .selectAll(".g")

          .data(data)

          .enter()

          .append("g")

          .on("mouseover", clumnMouseover)

          .on("mouseout", clumnMouseout)

          .attr("transform", function (d) {

          return (

          "translate(" +

          (d.ox + margin.left + 20) +

          "," +

          (svgHeight - margin.bottom + 15) +

          ")"

          );

          });

          g.transition()

          .duration(2500)

          .attr("transform", function (d) {

          return (

          "translate(" +

          (d.ox + margin.left + 20) +

          ", " +

          (yLinearScale(d.child.value) + margin.bottom - 15) +

          ")"

          );

          });

          g.append("rect")

          .attr("x", 0)

          .attr("y", 0)

          .attr("class", "transparentPath")

          .attr("width", function (d, i) {

          return d.ow;

          })

          .attr("height", function (d) {

          return d.oh;

          })

          .style("fill", function (d, i) {

          if (!mainColorList[i]) {

          return "#38a99d"

          }

          return mainColorList[i];

          })

          .transition()

          .duration(2500)

          .attr("height", function (d, i) {

          return (

          svgHeight -

          margin.bottom -

          margin.top -

          yLinearScale(d.child.value)

          );

          });

          g.append("path")

          .attr("class", "transparentPath")

          .attr("d", function (d) {

          return (

          "M0,0 L" +

          d.p1.x +

          "," +

          d.p1.y +

          " L" +

          d.p2.x +

          "," +

          d.p2.y +

          " L" +

          d.ow +

          ",0 L0,0"

          );

          })

          .style("fill", function (d, i) {

          if (!topColorList[i]) {

          return "#2da094"

          }

          return topColorList[i];

          });

          g.append("path")

          .attr("class", "transparentPath")

          .attr("d", function (d) {

          return (

          "M" +

          d.ow +

          ",0 L" +

          d.p2.x +

          "," +

          d.p2.y +

          " L" +

          d.p3.x +

          "," +

          d.p3.y +

          " L" +

          d.ow +

          "," +

          d.oh +

          " L" +

          d.ow +

          ",0"

          );

          })

          .style("fill", function (d, i) {

          if (!rightColorList[i]) {

          return "#2c9b8f"

          }

          return rightColorList[i];

          })

          .transition()

          .duration(2500)

          .attr("d", function (d, i) {

          return (

          "M" +

          d.ow +

          ",0 L" +

          d.p2.x +

          "," +

          d.p2.y +

          " L" +

          d.p3.x +

          "," +

          (d.p3.y +

          svgHeight -

          margin.top -

          margin.bottom -

          yLinearScale(d.child.value)) +

          " L" +

          d.ow +

          "," +

          (svgHeight -

          margin.top -

          margin.bottom -

          yLinearScale(d.child.value)) +

          " L" +

          d.ow +

          ",0"

          );

          });

          }

          // 函數調用

          addXAxis();

          addYScale();

          addColumn();

          }

          }

          這里提供暴露接口讓組件調用

          export function showCahrt(data, myEle) {

          return chart(data, myEle)

          }

          這里有個bug我一直沒有找到很好的解決辦法就是在繪制x軸時文字的樣式調整

          就是這里使用.attr("transform", "translate(0,20) rotate(-30deg)")也就是旋轉加下移組合是根本不生效只能寫其中的一個。不知道小伙伴們有沒有什么高見很是期待!

          整篇的代碼有點長其實整體還是很清晰的 。在最后面

          有收獲的小朋友記得點贊哦

          yecharts是一款將python與echarts結合的強大的數據可視化工具,本系列文章將為你闡述pyecharts的使用細則,讓你對數據進行可視化處理時更加得心應手。這一系列中全部代碼在Windows 10系統下基于Python3.7和pyecharts1.9.0實際運行通過。

          一、前言

          在本系列上一篇文章中筆者介紹了使用pyecharts繪制地理圖表的方法,運用pyecharts在繪制地圖方面有著特有的優勢,能動態且直觀的展現出繪制者想在地圖中表達的資源信息。在這一期文章里,筆者將介紹使用pyecharts繪制雷達圖、詞云圖、日歷圖等基本圖表。

          二、使用實例

          在本期文章中,我們需要導入的庫有:

          from pyecharts.charts import *
          from pyecharts.components import Table
          from pyecharts import options as opts
          from pyecharts.commons.utils import JsCode
          import  random
          import  datetime

          雷達圖是一種平行坐標圖,是一種從同一點開始的軸上表示多個定量或變量的二維圖表。雷達圖常用于繪制企業經營狀況、展現評價指標之間的關系,能夠直觀地查看各類數據指標及數據變化趨勢。

          雷達圖示例

          實現代碼:

          data=[
              [66, 91, 123, 78, 82, 67],
              [89, 101, 45, 88, 86, 75],
              [86, 93, 101, 84, 35, 73],
          ]
          radar=(Radar()
                   .add_schema(schema=[
                       opts.RadarIndicatorItem(name="語文", max_=150),
                       opts.RadarIndicatorItem(name="數學", max_=150),
                       opts.RadarIndicatorItem(name="英語", max_=150),
                       opts.RadarIndicatorItem(name="政治", max_=100),
                       opts.RadarIndicatorItem(name="地理", max_=100),
                       opts.RadarIndicatorItem(name="歷史", max_=100),
                   ]
          )
              .add('', data)
          )
          radar.render('雷達圖.html')

          詞云圖是一種以各種詞匯組成的二維圖表,一般用于提取大量文本中的關鍵字詞信息,使讀者能一眼掃過詞云圖便可以明白其主要內容和關鍵信息,同時也提高了閱讀文本的趣味性。

          詞云圖示例

          實現代碼:

          words=[
              ("heart", 173),
              ("no", 365),
              ("you", 360),
              ("can", 282),
              ("yes", 273),
              ("start", 265),
              ("hello", 365),
              ("world", 124),
              ("PPT", 436),
              ("frame", 255),
              ("Hadoop", 666),
              ("zookeeper", 244),
              ("goal", 681),
              ("today", 184),
              ("Monday", 12),
              ("last time", 148),
              ("configuration", 247),
              ("batter", 182),
              ("remember", 255),
              ("to", 150),
              ("make", 162),
              ("her", 266),
              ("in", 60),
              ("my", 82),
          ]
          wc=(
              WordCloud()
              .add("", words)
          )
          wc.render('詞云圖.html')

          日歷圖是一種能直觀顯示出對應日期的某個指標取值的動態圖表,利用pyecharts中的Calendar方法繪制日歷圖十分簡單。

          日歷圖示例

          實現代碼:

          begin=datetime.date(2021, 1, 1)
          end=datetime.date(2021, 10, 29)
          data=[[str(begin + datetime.timedelta(days=i)), random.randint(1000, 1200)]
                  for i in range((end - begin).days + 1)]
          
          calendar=(
              Calendar()
                  .add("", data,calendar_opts=opts.CalendarOpts(range_="2021"))
          )
          
          calendar.render('日歷圖.html')

          餅圖用于展現圖表中各項的大小與各項總和的比例,常在統計學中應用。

          餅圖示例

          實現代碼:

          cate=['meituan','zhifubao','weixin','taobao','jingdong','pinduoduo']
          data=[123,153,89,107,98,23]
          pie=(Pie()
                 .add('', [list(z) for z in zip(cate, data)])
                 )
          pie.render('餅圖.html')

          儀表盤圖是pyecharts中一種特有圖表,模仿汽車儀表盤碼速表,生動地展示某項數據的取值。

          儀表盤圖示例

          實現代碼:

          data=(
              '不及格率',
              12
          )
          gauge=(Gauge()
                    .add("", [data])
                    )
          gauge.render('儀表盤圖.html')

          水球圖同樣是pyecharts庫中一種特色圖表,用于展示某一項指標的取值。

          水球圖示例

          實現代碼:

          liquid=(Liquid()
                    .add("", [0.66, 0.34])
                    )
          liquid.render('水球圖.html')

          平行坐標圖用于展示在擁有高維度的評價指標情況下,各個評價對象之間的聯系和等級。

          平行坐標圖示例

          實現代碼:

          data=[
              ['301班', 78, 91, 123, 78, 82, 67, "優秀"],
              ['302班', 89, 101, 127, 88, 86, 75, "良好"],
              ['303班', 86, 93, 101, 84, 90, 73, "合格"],
          ]
          parallel=(
              Parallel()
              .add_schema(
                  [
                      opts.ParallelAxisOpts(
                          dim=0,
                          name="班級",
                          type_="category",
                          data=["301班", "302班", "303班"],
                      ),
                      opts.ParallelAxisOpts(dim=1, name="語文"),
                      opts.ParallelAxisOpts(dim=2, name="數學"),
                      opts.ParallelAxisOpts(dim=3, name="英語"),
                      opts.ParallelAxisOpts(dim=4, name="政治"),
                      opts.ParallelAxisOpts(dim=5, name="歷史"),
                      opts.ParallelAxisOpts(dim=6, name="地理"),
                      opts.ParallelAxisOpts(
                          dim=7,
                          name="等級",
                          type_="category",
                          data=["優秀", "良好", "合格"],
                      ),
                  ]
              )
              .add("", data)
          )
          parallel.render('平行坐標圖.html')

          旭日圖是一種特殊的餅圖,能清晰地表達層級和從屬關系,在pyecharts中我們使用Sunburst方法繪制。

          旭日圖示例

          實現代碼:

          data=[
              {"name": "廣東",
               "children": [
                       {"name": "廣州",
                        "children": [
                            {"name": "天河區", "value": 55},
                            {"name": "越秀區", "value": 34},
                            {"name": "增城區", "value": 66},
                        ]},
                       {"name": "東莞",
                        "children": [
                                {"name": "麻涌鎮", "value": 156},
                                {"name": "望牛墩鎮", "value": 134},
                        ]},
                       {"name": "汕頭", "value": 87},
                       {"name": "揭陽", "value": 23},
               ],
               },
              {"name": "新疆",
               "children": [
                       {"name": "烏魯木齊",
                        "children": [
                            {"name": "五家渠", "value": 55},
                            {"name": "昌吉", "value": 78},
                            {"name": "呼圖壁", "value": 34},
                        ]},
                       {"name": "阿克蘇", "value": 67},
                       {"name": "克拉瑪依", "value": 34},
               ],
               },
              {"name": "重慶", "value": 235}
          ]
          sunburst=(Sunburst()
                      .add("", data_pair=data)
                      )
          sunburst.render('旭日圖.html')

          河流圖是一種特殊的流圖,主要用于表示事件或主題在某一時間段內的變化情況。

          河流圖示例

          實現代碼:

          cate=['meituan','zhifubao','weixin','taobao','jingdong','pinduoduo']
          date_list=["2021/10/{}".format(i + 1) for i in range(30)]
          data=[[day, random.randint(10, 50), c] for day in date_list for c in cate]
          river=(
              ThemeRiver()
              .add(
                  series_name=cate,
                  data=data,
                  singleaxis_opts=opts.SingleAxisOpts(type_="time")
              )
          )
          river.render('河流圖.html')

          3D散點圖,用于展現三維數據在空間中的分布情況。

          3D散點圖示例

          實現代碼:

          data=[(random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)) for _ in range(100)]
          scatter3D=(Scatter3D()
                       .add("", data)
                       )
          scatter3D.render('3D散點圖.html')

          3D直方圖,用于展示三維數據在空間中的分布情況。

          3D直方圖示例

          實現代碼:

          data=[[i, j, random.randint(0, 100)] for i in range(24) for j in range(7)]
          hour_list=[str(i) for i in range(24)]
          week_list=['周日', '周一', '周二', '周三', '周四', '周五', '周六']
          bar3D=(
              Bar3D()
              .add(
                  "",
                  data,
                  xaxis3d_opts=opts.Axis3DOpts(hour_list, type_="category"),
                  yaxis3d_opts=opts.Axis3DOpts(week_list, type_="category"),
                  zaxis3d_opts=opts.Axis3DOpts(type_="value"),
              )
          )
          bar3D.render_notebook()

          以上就是這一期的全部內容,前三期內容筆者介紹了pyecharts庫的一些圖表的繪制方法,在這一系列的下一篇文章中筆者將介紹pyecharts庫中各個函數的配置項,熟練的使用配置項才能創造一個真正屬于自己的圖表。請各位等待下一期更新。

          文分享自華為云社區《[Python從零到壹] 五十四.圖像增強及運算篇之局部直方圖均衡化和自動色彩均衡化處理-云社區-華為云》,作者: eastmount。

          一.局部直方圖均衡化

          前文通過調用OpenCV中equalizeHist()函數實現直方圖均衡化處理,該方法簡單高效,但其實它是一種全局意義上的均衡化處理,很多時候這種操作不是很好,會把某些不該調整的部分給均衡處理了。同時,圖像中不同的區域灰度分布相差甚遠,對它們使用同一種變換常常產生不理想的效果,實際應用中,常常需要增強圖像的某些局部區域的細節。

          為了解決這類問題,Pizer等提出了局部直方圖均衡化的方法(AHE),但AHE方法僅僅考慮了局部區域的像素,忽略了圖像其他區域的像素,且對于圖像中相似區域具有過度放大噪聲的缺點。為此K. Zuiderveld等人提出了對比度受限CLAHE的圖像增強方法,通過限制局部直方圖的高度來限制局部對比度的增強幅度,從而限制噪聲的放大及局部對比度的過增強,該方法常用于圖像增強,也可以被用來進行圖像去霧操作[1-2]。

          在OpenCV中,調用函數createCLAHE()實現對比度受限的局部直方圖均衡化。它將整個圖像分成許多小塊(比如按10×10作為一個小塊),那么對每個小塊進行均衡化。這種方法主要對于圖像直方圖不是那么單一的(比如存在多峰情況)圖像比較實用。其函數原型如下所示:

          retval=createCLAHE([, clipLimit[, tileGridSize]])

          • clipLimit參數表示對比度的大小
          • tileGridSize參數表示每次處理塊的大小

          調用createCLAHE()實現對比度受限的局部直方圖均衡化的代碼如下:

          # -*- coding: utf-8 -*-
          # By:Eastmount
          import cv2  
          import numpy as np  
          import matplotlib.pyplot as plt
           
          #讀取圖片
          img=cv2.imread('lena.bmp')
          
          #灰度轉換
          gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
           
          #局部直方圖均衡化處理
          clahe=cv2.createCLAHE(clipLimit=2, tileGridSize=(10,10))
          
          #將灰度圖像和局部直方圖相關聯, 把直方圖均衡化應用到灰度圖 
          result=clahe.apply(gray)
          
          #顯示圖像
          plt.subplot(221)
          plt.imshow(gray, cmap=plt.cm.gray), plt.axis("off"), plt.title('(a)') 
          plt.subplot(222)
          plt.imshow(result, cmap=plt.cm.gray), plt.axis("off"), plt.title('(b)') 
          plt.subplot(223)
          plt.hist(img.ravel(), 256), plt.title('(c)') 
          plt.subplot(224)
          plt.hist(result.ravel(), 256), plt.title('(d)') 
          plt.show()
          

          輸出結果如圖1所示,圖1(a)為原始圖像,對應的直方圖為圖1?,圖1(b)和圖1(d)為對比度受限的局部直方圖均衡化處理后的圖像及對應直方圖,它讓圖像的灰度值分布更加均衡。可以看到,相對于全局的直方圖均衡化,這個局部的均衡化似乎得到的效果更自然一點。

          二.自動色彩均衡化

          Retinex算法是代表性的圖像增強算法,它根據人的視網膜和大腦皮層模擬對物體顏色的波長光線反射能力而形成,對復雜環境下的一維條碼具有一定范圍內的動態壓縮,對圖像邊緣有著一定自適應的增強。自動色彩均衡(Automatic Color Enhancement,ACE)算法是在Retinex算法的理論上提出的,它通過計算圖像目標像素點和周圍像素點的明暗程度及其關系來對最終的像素值進行校正,實現圖像的對比度調整,產生類似人體視網膜的色彩恒常性和亮度恒常性的均衡,具有很好的圖像增強效果[3-4]。

          ACE算法包括兩個步驟,一是對圖像進行色彩和空域調整,完成圖像的色差校正,得到空域重構圖像;二是對校正后的圖像進行動態擴展。ACE算法計算公式如下:

          其中,W是權重參數,離中心點像素越遠的W值越小;g是相對對比度調節參數,其計算方法如公式(22-2)所示,a表示控制參數,值越大細節增強越明顯。

          圖2是條形碼圖像進行ACE圖像增強后的效果圖,通過圖像增強后的圖(b)對比度更強,改善了原圖像的明暗程度,增強的同時保持了圖像的真實性。

          由于OpenCV中暫時沒有ACE算法包,下面的代碼是借鑒“zmshy2128”老師的文章,修改實現的彩色直方圖均衡化處理[5]。

          # -*- coding: utf-8 -*-
          # By:Eastmount
          # 參考zmshy2128老師文章
          import cv2
          import numpy as np
          import math
          import matplotlib.pyplot as plt
          
          #線性拉伸處理
          #去掉最大最小0.5%的像素值 線性拉伸至[0,1]
          def stretchImage(data, s=0.005, bins=2000):   
              ht=np.histogram(data, bins);
              d=np.cumsum(ht[0])/float(data.size)
              lmin=0; lmax=bins-1
              while lmin<bins:
                  if d[lmin]>=s:
                      break
                  lmin+=1
              while lmax>=0:
                  if d[lmax]<=1-s:
                      break
                  lmax-=1
              return np.clip((data-ht[1][lmin])/(ht[1][lmax]-ht[1][lmin]), 0,1)
          
          #根據半徑計算權重參數矩陣
          g_para={}
          def getPara(radius=5):                        
              global g_para
              m=g_para.get(radius, None)
              if m is not None:
                  return m
              size=radius*2+1
              m=np.zeros((size, size))
              for h in range(-radius, radius+1):
                  for w in range(-radius, radius+1):
                      if h==0 and w==0:
                          continue
                      m[radius+h, radius+w]=1.0/math.sqrt(h**2+w**2)
              m /=m.sum()
              g_para[radius]=m
              return m
          
          #常規的ACE實現
          def zmIce(I, ratio=4, radius=300):                     
              para=getPara(radius)
              height,width=I.shape
              
              #Python3報錯如下 使用列表append修改
              zh=[]
              zw=[]
              n=0
              while n < radius:
                  zh.append(0)
                  zw.append(0)
                  n +=1
              for n in range(height):
                  zh.append(n)
              for n in range(width):
                  zw.append(n)
              n=0
              while n < radius:
                  zh.append(height-1)
                  zw.append(width-1)
                  n +=1
              #print(zh)
              #print(zw)
              
              Z=I[np.ix_(zh, zw)]
              res=np.zeros(I.shape)
              for h in range(radius*2+1):
                  for w in range(radius*2+1):
                      if para[h][w]==0:
                          continue
                      res +=(para[h][w] * np.clip((I-Z[h:h+height, w:w+width])*ratio, -1, 1))
              return res
          
          #單通道ACE快速增強實現
          def zmIceFast(I, ratio, radius):
              print(I)
              height, width=I.shape[:2]
              if min(height, width) <=2:
                  return np.zeros(I.shape)+0.5
              Rs=cv2.resize(I, (int((width+1)/2), int((height+1)/2)))
              Rf=zmIceFast(Rs, ratio, radius)             #遞歸調用
              Rf=cv2.resize(Rf, (width, height))
              Rs=cv2.resize(Rs, (width, height))
           
              return Rf+zmIce(I,ratio, radius)-zmIce(Rs,ratio,radius)   
          
          #rgb三通道分別增強 ratio是對比度增強因子 radius是卷積模板半徑          
          def zmIceColor(I, ratio=4, radius=3):               
              res=np.zeros(I.shape)
              for k in range(3):
                  res[:,:,k]=stretchImage(zmIceFast(I[:,:,k], ratio, radius))
              return res
          
          #主函數
          if __name__=='__main__':
              img=cv2.imread('test01.png')
              res=zmIceColor(img/255.0)*255
              cv2.imwrite('Ice.jpg', res)
          

          運行結果如圖3和圖4所示,ACE算法能有效進行圖像去霧處理,實現圖像的細節增強。

          三.總結

          本文主要講解圖像局部直方圖均衡化和自動色彩均衡化處理。這些算法可以廣泛應用于圖像增強、圖像去噪、圖像去霧等領域。

          參考文獻:

          • [1]王浩,張葉,沈宏海,張景忠.圖像增強算法綜述[J].中國光學,2017,10(04):438-448.
          • [2]李艷梅. 圖像增強的相關技術及應用研究[D].電子科技大學,2013.
          • [3]S. Bidon, Olivier Besson, J. Y. Tourneret. The Adaptive Coherence Estimator is the Generalized Likelihood Ratio Test for a Class of Heterogeneous Environments[J]. IEEE Signal Processing Letters, 2008, 15: 281-284.
          • [4]eastmount. [Python圖像處理] 三十八.OpenCV圖像增強和圖像去霧萬字詳解(直方圖均衡化、局部直方圖均衡化、自動色彩均衡化)[EB/OL]. (2021-03-12). https://blog.csdn.net/ Eastmount/article/details/114706950.
          • [5]zmshy2128. 自動色彩均衡(ACE)快速算法[EB/OL]. (2016-12-05). https://www.cnblogs.com/zmshy2128/p/6135551.html.

          點擊下方,第一時間了解華為云新鮮技術~

          華為云博客_大數據博客_AI博客_云計算博客_開發者中心-華為云


          主站蜘蛛池模板: 精品国产AⅤ一区二区三区4区 | 国产精品日韩一区二区三区| 亚洲国产一区在线观看| 亚洲AV成人一区二区三区AV| 婷婷国产成人精品一区二| 一区二区三区四区视频| 日韩在线一区视频| 99精品国产一区二区三区2021| 国产一区韩国女主播| 2021国产精品一区二区在线 | 国产日本一区二区三区| 欧美日本精品一区二区三区| 一区二区三区国产| 国产天堂一区二区综合| 中文字幕无码免费久久9一区9| 精品乱人伦一区二区| 午夜无码视频一区二区三区| 亚洲AV无码一区二区三区鸳鸯影院| 精品人妻中文av一区二区三区| 久久精品岛国av一区二区无码| 无码精品视频一区二区三区| 亚拍精品一区二区三区| 无码国产精品一区二区免费 | 亚洲AV福利天堂一区二区三| 久久人妻av一区二区软件| 亚洲av乱码中文一区二区三区| www一区二区三区| 一夲道无码人妻精品一区二区| 99在线精品一区二区三区| 久久国产高清一区二区三区| 亚洲一区二区三区高清不卡 | 日韩一区二区三区不卡视频| 少妇无码一区二区三区| 国产综合无码一区二区三区| 精品中文字幕一区二区三区四区 | 97久久精品午夜一区二区| 国产乱码一区二区三区爽爽爽| 国产精品制服丝袜一区| 真实国产乱子伦精品一区二区三区| 在线精品国产一区二区| AV天堂午夜精品一区|