using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.IO;
using System.Collections;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ArucoModule;
using OpenCVForUnity.ImgcodecsModule;
using OpenCVForUnity.UnityUtils;
namespace OpenCVForUnityExample
{
///
/// ArUco Create Marker Example
/// Referring to https://github.com/opencv/opencv_contrib/blob/master/modules/aruco/samples/create_marker.cpp.
///
public class ArUcoCreateMarkerExample : MonoBehaviour
{
///
/// The size of the output marker image (px).
///
public int markerSize = 1000;
///
/// The marker type.
///
public MarkerType markerType = MarkerType.CanonicalMarker;
///
/// The marker type dropdown.
///
public Dropdown markerTypeDropdown;
///
/// The dictionary identifier.
///
public ArUcoDictionary dictionaryId = ArUcoDictionary.DICT_6X6_250;
///
/// The dictionary id dropdown.
///
public Dropdown dictionaryIdDropdown;
///
/// The marker identifier.
///
public MarkerID markerId = MarkerID.MarkerID_1;
///
/// The marker id dropdown.
///
public Dropdown markerIdDropdown;
///
/// The save path input field.
///
public InputField savePathInputField;
///
/// The marker img mat.
///
Mat markerImg;
///
/// The texture.
///
Texture2D texture;
// width of the marker borders.
const int borderBits = 1;
// for GridBoard.
// number of markers in X direction
const int gridBoradMarkersX = 5;
// number of markers in Y direction
const int gridBoradMarkersY = 7;
// marker side length (normally in meters)
const float gridBoradMarkerLength = 0.04f;
// separation between two markers (same unit as markerLength)
const float gridBoradMarkerSeparation = 0.01f;
// id of first marker in dictionary to use on board.
const int gridBoradMarkerFirstMarker = 0;
// minimum margins (in pixels) of the board in the output image
const int gridBoradMarginSize = 10;
// for ChArUcoBoard.
// number of chessboard squares in X direction
const int chArUcoBoradMarkersX = 5;
// number of chessboard squares in Y direction
const int chArUcoBoradMarkersY = 7;
// chessboard square side length (normally in meters)
const float chArUcoBoradSquareLength = 0.04f;
// marker side length (same unit than squareLength)
const float chArUcoBoradMarkerLength = 0.02f;
// minimum margins (in pixels) of the board in the output image
const int chArUcoBoradMarginSize = 10;
// Use this for initialization
void Start ()
{
markerImg = new Mat (markerSize, markerSize, CvType.CV_8UC3);
texture = new Texture2D (markerImg.cols (), markerImg.rows (), TextureFormat.RGB24, false);
gameObject.GetComponent ().material.mainTexture = texture;
markerTypeDropdown.value = (int)markerType;
markerIdDropdown.value = (int)markerId;
dictionaryIdDropdown.value = (int)dictionaryId;
CreateMaeker ();
}
// Update is called once per frame
void Update ()
{
}
private void CreateMaeker ()
{
if (markerImg.cols () != markerSize) {
markerImg.Dispose ();
markerImg = new Mat (markerSize, markerSize, CvType.CV_8UC3);
texture = new Texture2D (markerImg.cols (), markerImg.rows (), TextureFormat.RGB24, false);
} else {
markerImg.setTo (Scalar.all (255));
}
gameObject.transform.localScale = new Vector3 (markerImg.cols (), markerImg.rows (), 1);
float width = markerImg.width () / 0.7f;
float height = markerImg.height () / 0.7f;
float widthScale = (float)Screen.width / width;
float heightScale = (float)Screen.height / height;
if (widthScale < heightScale) {
Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
gameObject.transform.localPosition = new Vector3 (0, -height * 0.1f, 0);
} else {
Camera.main.orthographicSize = height / 2;
gameObject.transform.localPosition = new Vector3 (width * 0.1f, 0, 0);
}
// create dictinary.
Dictionary dictionary = Aruco.getPredefinedDictionary ((int)dictionaryId);
// draw marker.
switch (markerType) {
default:
case MarkerType.CanonicalMarker:
Aruco.drawMarker (dictionary, (int)markerId, markerSize, markerImg, borderBits);
Debug.Log ("draw CanonicalMarker: " + "dictionaryId " + (int)dictionaryId + " markerId " + (int)markerId + " sidePixels " + markerSize + " borderBits " + borderBits);
break;
case MarkerType.GridBoard:
GridBoard gridBoard = GridBoard.create (gridBoradMarkersX, gridBoradMarkersY, gridBoradMarkerLength, gridBoradMarkerSeparation, dictionary, gridBoradMarkerFirstMarker);
gridBoard.draw (new Size (markerSize, markerSize), markerImg, gridBoradMarginSize, borderBits);
gridBoard.Dispose ();
Debug.Log ("draw GridBoard: " + "markersX " + gridBoradMarkersX + " markersY " + gridBoradMarkersY + " markerLength " + gridBoradMarkerLength +
" markerSeparation " + gridBoradMarkerSeparation + "dictionaryId " + (int)dictionaryId + " outSize " + markerSize + " marginSize " + gridBoradMarginSize + " borderBits " + borderBits);
break;
case MarkerType.ChArUcoBoard:
CharucoBoard charucoBoard = CharucoBoard.create (chArUcoBoradMarkersX, chArUcoBoradMarkersY, chArUcoBoradSquareLength, chArUcoBoradMarkerLength, dictionary);
charucoBoard.draw (new Size (markerSize, markerSize), markerImg, chArUcoBoradMarginSize, borderBits);
charucoBoard.Dispose ();
Debug.Log ("draw ChArUcoBoard: " + "markersX " + chArUcoBoradMarkersX + " markersY " + chArUcoBoradMarkersY + " markerLength " + chArUcoBoradSquareLength +
" markerSeparation " + chArUcoBoradMarkerLength + "dictionaryId " + (int)dictionaryId + " outSize " + markerSize + " marginSize " + chArUcoBoradMarginSize + " borderBits " + borderBits);
break;
}
Utils.matToTexture2D (markerImg, texture, true, 0, true);
}
private void SaveMarkerImg ()
{
// save the markerImg.
string saveDirectoryPath = Path.Combine (Application.persistentDataPath, "ArUcoCreateMarkerExample");
string savePath = "";
#if UNITY_WEBGL && !UNITY_EDITOR
string format = "jpg";
MatOfInt compressionParams = new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 100);
#else
string format = "png";
MatOfInt compressionParams = new MatOfInt (Imgcodecs.IMWRITE_PNG_COMPRESSION, 0);
#endif
switch (markerType) {
default:
case MarkerType.CanonicalMarker:
savePath = Path.Combine (saveDirectoryPath, "CanonicalMarker-d" + (int)dictionaryId + "-i" + (int)markerId + "-sp" + markerSize + "-bb" + borderBits + "." + format);
break;
case MarkerType.GridBoard:
savePath = Path.Combine (saveDirectoryPath, "GridBoard-mx" + gridBoradMarkersX + "-my" + gridBoradMarkersY + "-d" + (int)dictionaryId + "-os" + markerSize + "-bb" + borderBits + "." + format);
break;
case MarkerType.ChArUcoBoard:
savePath = Path.Combine (saveDirectoryPath, "ChArUcoBoard-mx" + chArUcoBoradMarkersX + "-my" + chArUcoBoradMarkersY + "-d" + (int)dictionaryId + "-os" + markerSize + "-bb" + borderBits + "." + format);
break;
}
if (!Directory.Exists (saveDirectoryPath)) {
Directory.CreateDirectory (saveDirectoryPath);
}
Imgcodecs.imwrite (savePath, markerImg, compressionParams);
savePathInputField.text = savePath;
Debug.Log ("savePath: " + savePath);
}
///
/// Raises the destroy event.
///
void OnDestroy ()
{
if (markerImg != null)
markerImg.Dispose ();
}
///
/// Raises the back button click event.
///
public void OnBackButtonClick ()
{
SceneManager.LoadScene ("OpenCVForUnityExample");
}
///
/// Raises the marker type dropdown value changed event.
///
public void OnMarkerTypeDropdownValueChanged (int result)
{
if ((int)markerType != result) {
markerType = (MarkerType)result;
markerIdDropdown.interactable = (markerType == MarkerType.CanonicalMarker);
CreateMaeker ();
}
}
///
/// Raises the dictionary id dropdown value changed event.
///
public void OnDictionaryIdDropdownValueChanged (int result)
{
if ((int)dictionaryId != result) {
dictionaryId = (ArUcoDictionary)result;
CreateMaeker ();
}
}
///
/// Raises the marker id dropdown value changed event.
///
public void OnMarkerIdDropdownValueChanged (int result)
{
if ((int)markerId != result) {
markerId = (MarkerID)result;
CreateMaeker ();
}
}
///
/// Raises the save marker img button click event.
///
public void OnSaveMarkerImgButtonClick ()
{
SaveMarkerImg ();
}
public enum MarkerType
{
CanonicalMarker,
GridBoard,
ChArUcoBoard,
//ChArUcoDiamondMarker //Not yet implemented.
}
public enum ArUcoDictionary
{
DICT_4X4_50 = Aruco.DICT_4X4_50,
DICT_4X4_100 = Aruco.DICT_4X4_100,
DICT_4X4_250 = Aruco.DICT_4X4_250,
DICT_4X4_1000 = Aruco.DICT_4X4_1000,
DICT_5X5_50 = Aruco.DICT_5X5_50,
DICT_5X5_100 = Aruco.DICT_5X5_100,
DICT_5X5_250 = Aruco.DICT_5X5_250,
DICT_5X5_1000 = Aruco.DICT_5X5_1000,
DICT_6X6_50 = Aruco.DICT_6X6_50,
DICT_6X6_100 = Aruco.DICT_6X6_100,
DICT_6X6_250 = Aruco.DICT_6X6_250,
DICT_6X6_1000 = Aruco.DICT_6X6_1000,
DICT_7X7_50 = Aruco.DICT_7X7_50,
DICT_7X7_100 = Aruco.DICT_7X7_100,
DICT_7X7_250 = Aruco.DICT_7X7_250,
DICT_7X7_1000 = Aruco.DICT_7X7_1000,
DICT_ARUCO_ORIGINAL = Aruco.DICT_ARUCO_ORIGINAL,
}
public enum MarkerID
{
MarkerID_0,
MarkerID_1,
MarkerID_2,
MarkerID_3,
MarkerID_4,
MarkerID_5,
MarkerID_6,
MarkerID_7,
MarkerID_8,
MarkerID_9,
}
}
}