2016年10月19日 星期三

同學問題答覆_如何去除png影像貼上去之後仍有白色背景的像素數值殘留

上回

幫同學示範了  如何貼圖的  功能  以及 ROI 設置的方式 偵測人臉等示範



但是效果有白色殘留   即便是 png  影像  仍然會有 白色殘留不乾淨等效果
不好看

這裡我們探討到 如何只取得我們所要的帽子區域的顏色像素數值


完整處理流程

首先針對載入的原影像進行 ROI 設置



設置好了之後



我們載入預先你已經挑好的物件(要貼的東西圖檔)這裡我是採用jpg圖檔

Step1. 為了進行範圍的設置 我們要將區塊進行二值化的設置

所以要先將物件轉灰階

Step2. 緊接著 你可以試著定義一個門檻數值 這裡你會發現  jpg圖檔
由於白色區塊的 0~255數值 它 有些區域是  252 有些是  253  有些是254 、 255

所以會有不乾淨的感覺

門檻值設置  就是指  設定一個門檻  大於此門檻的話我就通通設為255(白色)
其餘為黑色  這裡我們稱之為遮罩的設置


Step3. 將這個物件已經取出的顏色遮罩進行反色的處理



未進行反色處理前直接貼上去會是此效果
黑色部分由於都是0  相當於挖了一個空洞

其餘部分則是 255  白色

這也是為何要進行反色喔!!!!




png 跟 jpg 作法上類似

只是 jpg 比較會有 剛才講的白色髒髒的感覺

png 可以試試看




2016年10月17日 星期一

emgucv_著色示範_row-major_vs_column-major_靜/動態影像貼圖_示範_商業應用

首先新增好一個  C# 專案 並配置好emgucv

這裡我先示範一個

載入靜態圖的範例

row-major_vs_column-major

簡易視窗配置


如何鎖住  imageBox 物件的 滾輪自動放大縮小功能

以及 右鍵  作效果等功能

右側  --->  找到  Functional Mode 把 預設的 Everything 改成



這樣可以將emgucv  imageBox物件提供的右鍵及滾輪縮放等功能先鎖住!!!!!!



練習畫圖的部分



第一階段程式碼



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.ML;

namespace emgucv_note
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Image<Bgr, byte> imgBg = new Image<Bgr, byte>(512, 512); //畫布  空的  預設黑色           
            //備註:Image<Gray, byte>   預設也是黑色喔!!!

            imageBox1.Image = imgBg;
        }

    }
}




怎麼改變畫布顏色呢??



                                                                            示意圖


第二階段程式碼 _改變背景色 


第一種寫法


imgBg.Data[i, j, 0] = 255;


代碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.ML;

namespace emgucv_note
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Image<Bgr, byte> imgBg = new Image<Bgr, byte>(512, 512);            
            //Image<Gray, byte> imgGrayBg = new Image<Gray, byte>(512, 512);
            for(int i=0;i<imgBg.Width;i++)
                for(int j=0;j<imgBg.Height;j++)
                {
                    imgBg.Data[i, j, 0] = 255; //B
                    imgBg.Data[i, j, 1] = 0;   //G
                    imgBg.Data[i, j, 2] = 0;   //R
                }
            imageBox1.Image = imgBg;
        }

    }
}



第二種寫法

先取出  畫布資料用  Byte陣列存



代碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.ML;

namespace emgucv_note
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Image<Bgr, byte> imgBg = new Image<Bgr, byte>(512, 512);
            //Image<Gray, byte> imgGrayBg = new Image<Gray, byte>(512, 512);

            byte[] imgTmp = imgBg.Bytes;

            for(int i=0;i<imgBg.Width;i++)
                for(int j=0;j<imgBg.Height;j++)
                {
                    int n = i * imgBg.Width + j; // row-major 的 寫法
                    imgTmp[n * 3] = 0; //B
                    imgTmp[n * 3 + 1] = 255;//G
                    imgTmp[n * 3 + 2] = 0;//R
                }
            imgBg.Bytes = imgTmp;
            imageBox1.Image = imgBg;
        }
    }
}





row-major










A row-major ordered matrix. Elements are stored in memory in the order shown by the arrow.





column-major

















A column-major ordered matrix. Elements are stored in memory in the order shown by the arrow.



靜/動態影像貼圖_示範

商業應用

SNOW - 自拍、臉部辨識貼圖、超有趣相機




Photo Booth 拍照系統






Kinect 拍照系統  宜達國際股份有限公司  工讀合作案  (from 班導)

http://www.pro-fotoimagic.com.tw/about.html

Kinect V2 部分  :  學習自   微軟MVP  Vangos Pterneas  

http://pterneas.com/

WPF視窗程式部份 : 學習自 游寶達教授  及其 助教  蔡政宇 博士生

https://www.youtube.com/watch?v=s5Hrgl0OD2w&list=PLcOD6drVLxLNBW4I37Ei5-Aq2zaJXRV5E&index=1
  

完成了第一階段收穫及心得 :  

我比其他人多學會一種視窗程式語言、視窗真的滿多公司要求的  嗚嗚嗚  不能只會opencv

還有自學完成了這個第一階段  十分有成就感  呼呼~~ YA

希望後續能繼續順利  結論:從完全不會但是善用youtube就可以成就一些事情



宜達國際股份有限公司  工讀合作案

工作要求:

第一階段

幫忙寫出

Kinect 去背效果然後要可以選取背景

要有視窗介面

要可以切換畫面(進行跳頁)

不可顯示上方醜陋工具列(放大/縮小/關閉的視窗列)

第二階段

要加上相框(融入背景後的壓前框) 進行拍照存檔

寫出臉部偵測  進行趣味貼圖


題外話   扯遠了~~~~








首先我們先新增一個C#專案






第一階段 _ 先秀靜態圖 成功讀取顯示一張個人照片


第一階段讀圖程式碼


第二階段  人臉偵測示範

效果




多添加了一個  button 用來做  偵測  當然準確率會有誤差  

使用 emgucv bin 目錄下 提供的 haarcascade_frontalface_default  的 xml 進行人臉偵測




將此檔案放置於你程式專案的

同學這裡告訴你一個小秘密
去下載opencv之後
在目錄下的

這裡都可以做使用喔!!!



第二階段 人臉偵測示範 程式碼:



如果想學習  opencv 版本  可以參考下方兩個link


Opencv_臉譜分類器_研究_part1(臉部到眼睛_CascadeClassifier類介紹_參數)
http://coolmandiary.blogspot.tw/2016/01/opencv.html

Opencv_臉譜分類器_研究_part2(如何貼面具在臉部實現戴面具效果)
http://coolmandiary.blogspot.tw/2016/02/opencvpart2.html

opencv_海爾訓練剖析_L1

http://coolmandiary.blogspot.tw/2016/05/opencvl1.html
第三階段  靜態圖上貼圖_示範

自己上網找 帽子的圖

如果有現成的png圖檔再好不過
沒有就自己去去背





去背線上網站工具推薦







https://burner.bonanza.com/

Photoshop 去背簡易教學


https://www.youtube.com/watch?v=AZc3jb3L3BI


貼一張圖上去

貼  png 的效果



程式碼小示範








這是未去背直接貼上去的效果




那這裡呢  教大家一招  帥招

首先我們去  小畫家  把  帽子 這張 jpg 圖檔

被景色  改為  黑色





程式碼 做點小更改




先讓小塊的帽子影像跟原圖的感興趣區塊相加

然後再貼到原圖上面去

這裡我們就可以改高度及寬度了

改到合適區塊





目前程式碼



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.CvEnum;

namespace emgucv_paste_exercise
{
    public partial class Form1 : Form
    {
        #region Globle Var
        Image<Bgr, byte> img;
        #endregion


        public Form1()
        {
            InitializeComponent();
        }

        private void btnOpenImage_Click(object sender, EventArgs e)
        {
            string strFileName = string.Empty;

            OpenFileDialog ofd = new OpenFileDialog();
            if(ofd.ShowDialog() == DialogResult.OK)
            {
                img = new Image<Bgr, byte>(ofd.FileName);
                pictureBox1.Image = img.ToBitmap();
            }
        }

        private void btnStaticPaste_Click(object sender, EventArgs e)
        {
            string strFileName = string.Empty;            
            OpenFileDialog ofd = new OpenFileDialog();
            Image<Bgr, byte> texture ;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                texture = new Image<Bgr, byte>(ofd.FileName);
                img.ROI = new Rectangle(img.Width/2-45, img.Height/4-65, texture.Width, texture.Height);
                texture = texture + img;
                texture.CopyTo(img);
                img.ROI = new Rectangle();
                pictureBox1.Image = img.ToBitmap();
            }
        }

        private void btnFaceDetect_Click(object sender, EventArgs e)
        {
            List<Rectangle> faces = new List<Rectangle>();

            CascadeClassifier face = new CascadeClassifier("haarcascade_frontalface_alt.xml");

            Image<Gray, byte> grayImg = img.Convert<Gray, byte>();

            //Face Detect 
            Rectangle[] faceDetected = face.DetectMultiScale(grayImg,
                                                                1.1,
                                                                10,
                                                                new Size(30,30),
                                                                Size.Empty);
            faces.AddRange(faceDetected);
            
            foreach (Rectangle f in faces)
            {
                img.Draw(f, new Bgr(Color.Red), 2);
            }            

            pictureBox1.Image = img.ToBitmap();
        }
    }
}





目前先示範到  這裡  同學加油吧  !!!!  GO  GO