Android学习——在Android中使用OpenCV的第一个程序
刚開始学习Android,因为之前比較熟悉OpenCV,于是就想先在Android上执行OpenCV试试
===================================================================================
1.环境配置
- JDK
- Eclipse
- ADT
- CDT
- Android SDK
- Android NDK
- cygwin
- OpenCV for Android 2.4.9
这部分网上非常多。我就不再赘述了,能够參考:http://blog.csdn.net/pwh0996/article/details/8957764
2.开发准备
两点注意
- 新版安装SDK文件一開始有两个XML文件,activity_main.xml和fragment_main.xml:不习惯的能够这样处理:
- 删除fragment_main.xml整个文件
- 对activity_main.xml,删除里面的内容。然后切换到Graphy Layout,放入一个LinearLayout就能够
- 对MainActivity.java。能够删除部分的内容,再把MainActivity extends ActionBarActivity 改为MainActivity extends Activity
- (关于activity_main.xml与fragment_main.xml的问题參看:http://bbs.csdn.net/topics/390740123)
- 引入OpenCV库Package Explorer中选择项目,单击右键在弹出菜单中选择Properties,然后在弹出的Properties窗体中左側选择Android。然后点击右下方的Addbutton,选择OpenCV Library 2.4.9并点击OK。操作完毕后,会将OpenCV类库加入到GrayProcess的Android Dependencies中
- CameraBridgeViewBase .enableView()
- SurfaceView is available
- CameraBridgeViewBase .setVisibility(SurfaceView.Visiable)
- CameraBridgeViewBase .setCvCameraViewListener(this)
- onCameraViewStarted
- onCameraViewStopped
- public Mat onCameraFrame(CvCameraViewFrame inputFrame)
Java文件:
public class MainActivity extends Activity implements CvCameraViewListener2 {
private static final String TAG = "OCVSample::Activity";
private CameraBridgeViewBase mOpenCvCameraView;
private boolean mIsJavaCamera = true;
private MenuItem mItemSwitchCamera = null;
private Mat mRgba;
private Button mBtn = null;
private boolean isProcess = false;
//建立连接
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
//构造函数
public MainActivity() {
Log.i(TAG, "Instantiated new " + this.getClass());
}
/** Called when the activity is first created. */
//onCreate函数
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
//
if (mIsJavaCamera)
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
else
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
mBtn = (Button) findViewById(R.id.buttonGray);
mBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
isProcess = !isProcess;
}
});
}
@Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this, mLoaderCallback);
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i(TAG, "called onCreateOptionsMenu");
mItemSwitchCamera = menu.add("Toggle Native/Java camera");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
String toastMesage = new String();
Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
if (item == mItemSwitchCamera) {
mOpenCvCameraView.setVisibility(SurfaceView.GONE);
mIsJavaCamera = !mIsJavaCamera;
if (mIsJavaCamera) {
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
toastMesage = "Java Camera";
} else {
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);
toastMesage = "Native Camera";
}
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
mOpenCvCameraView.enableView();
Toast toast = Toast.makeText(this, toastMesage, Toast.LENGTH_LONG);
toast.show();
}
return true;
}
public void onCameraViewStarted(int width, int height) {
mRgba = new Mat(height, width, CvType.CV_8UC4);
}
public void onCameraViewStopped() {
mRgba.release();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
if(isProcess)
Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
else
mRgba = inputFrame.rgba();
return mRgba;
}
}
<uses-permission android:name="android.permission.CAMERA"/>
mCamera.setDisplayOrientation(90);
在OpenCV
for Android的开发中,在Manifest文件里增加:
android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.camera03"
android:versionCode="1"
android:versionName="1.0" > <supports-screens android:resizeable="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true" />
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.CAMERA"/> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<activity
android:name="com.example.camera03.MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application> </manifest>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" > <org.opencv.android.JavaCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="@+id/tutorial1_activity_java_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" /> <org.opencv.android.NativeCameraView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:id="@+id/tutorial1_activity_native_surface_view"
opencv:show_fps="true"
opencv:camera_id="any" /> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" > <Button
android:id="@+id/buttonGray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/buttonGray" /> </RelativeLayout> </FrameLayout>
- 原图
- 灰度图
- Canny边缘检測
- Hist 直方图计算
- Sobel 边缘检測
- SEPIA(色调变换)为每个数组元素运行一个矩阵变换
- ZOOM 放大镜
- PIXELIZE 像素化
- POSTERIZE 多色调分色印
package com.example.camera03; import java.util.Arrays; import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2; import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast; public class MainActivity extends Activity implements CvCameraViewListener2 {
private static final String TAG = "OCVSample::Activity"; private CameraBridgeViewBase mOpenCvCameraView;
private boolean mIsJavaCamera = true;
private MenuItem mItemSwitchCamera = null;
private Mat mRgba;
private Mat mGray;
private Mat mTmp; private Size mSize0;
private Mat mIntermediateMat;
private MatOfInt mChannels[];
private MatOfInt mHistSize;
private int mHistSizeNum = 25;
private Mat mMat0;
private float[] mBuff;
private MatOfFloat mRanges;
private Point mP1;
private Point mP2;
private Scalar mColorsRGB[];
private Scalar mColorsHue[];
private Scalar mWhilte;
private Mat mSepiaKernel;
private Button mBtn = null;
private int mProcessMethod = 0; private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
}; public MainActivity() {
Log.i(TAG, "Instantiated new " + this.getClass());
} /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_main); if (mIsJavaCamera)
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
else
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view); mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE); mOpenCvCameraView.setCvCameraViewListener(this); mBtn = (Button) findViewById(R.id.buttonGray);
mBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
mProcessMethod++;
if(mProcessMethod>8) mProcessMethod=0;
}
});
} @Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
} @Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this, mLoaderCallback);
} public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i(TAG, "called onCreateOptionsMenu");
mItemSwitchCamera = menu.add("Toggle Native/Java camera");
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
String toastMesage = new String();
Log.i(TAG, "called onOptionsItemSelected; selected item: " + item); if (item == mItemSwitchCamera) {
mOpenCvCameraView.setVisibility(SurfaceView.GONE);
mIsJavaCamera = !mIsJavaCamera; if (mIsJavaCamera) {
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
toastMesage = "Java Camera";
} else {
mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);
toastMesage = "Native Camera";
} mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
mOpenCvCameraView.enableView();
Toast toast = Toast.makeText(this, toastMesage, Toast.LENGTH_LONG);
toast.show();
} return true;
} public void onCameraViewStarted(int width, int height) {
mRgba = new Mat(height, width, CvType.CV_8UC4);
mGray = new Mat(height, width, CvType.CV_8UC1);
mTmp = new Mat(height, width, CvType.CV_8UC4); mIntermediateMat = new Mat();
mSize0 = new Size();
mChannels = new MatOfInt[] { new MatOfInt(0), new MatOfInt(1), new MatOfInt(2) };
mBuff = new float[mHistSizeNum];
mHistSize = new MatOfInt(mHistSizeNum);
mRanges = new MatOfFloat(0f, 256f);
mMat0 = new Mat();
mColorsRGB = new Scalar[] { new Scalar(200, 0, 0, 255), new Scalar(0, 200, 0, 255), new Scalar(0, 0, 200, 255) };
mColorsHue = new Scalar[] {
new Scalar(255, 0, 0, 255), new Scalar(255, 60, 0, 255), new Scalar(255, 120, 0, 255), new Scalar(255, 180, 0, 255), new Scalar(255, 240, 0, 255),
new Scalar(215, 213, 0, 255), new Scalar(150, 255, 0, 255), new Scalar(85, 255, 0, 255), new Scalar(20, 255, 0, 255), new Scalar(0, 255, 30, 255),
new Scalar(0, 255, 85, 255), new Scalar(0, 255, 150, 255), new Scalar(0, 255, 215, 255), new Scalar(0, 234, 255, 255), new Scalar(0, 170, 255, 255),
new Scalar(0, 120, 255, 255), new Scalar(0, 60, 255, 255), new Scalar(0, 0, 255, 255), new Scalar(64, 0, 255, 255), new Scalar(120, 0, 255, 255),
new Scalar(180, 0, 255, 255), new Scalar(255, 0, 255, 255), new Scalar(255, 0, 215, 255), new Scalar(255, 0, 85, 255), new Scalar(255, 0, 0, 255)
};
mWhilte = Scalar.all(255);
mP1 = new Point();
mP2 = new Point(); // Fill sepia kernel
mSepiaKernel = new Mat(4, 4, CvType.CV_32F);
mSepiaKernel.put(0, 0, /* R */0.189f, 0.769f, 0.393f, 0f);
mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);
mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);
mSepiaKernel.put(3, 0, /* A */0.000f, 0.000f, 0.000f, 1f);
} public void onCameraViewStopped() {
mRgba.release();
mGray.release();
mTmp.release();
} public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba();
Size sizeRgba = mRgba.size();
int rows = (int) sizeRgba.height;
int cols = (int) sizeRgba.width;
Mat rgbaInnerWindow; int left = cols / 8;
int top = rows / 8; int width = cols * 3 / 4;
int height = rows * 3 / 4;
//灰度图
if(mProcessMethod==1)
Imgproc.cvtColor(inputFrame.gray(), mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
//Canny边缘检測
else if(mProcessMethod==2)
{
mRgba = inputFrame.rgba();
Imgproc.Canny(inputFrame.gray(), mTmp, 80, 100);
Imgproc.cvtColor(mTmp, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);
}
//Hist
else if(mProcessMethod==3)
{
Mat hist = new Mat();
int thikness = (int) (sizeRgba.width / (mHistSizeNum + 10) / 5);
if(thikness > 5) thikness = 5;
int offset = (int) ((sizeRgba.width - (5*mHistSizeNum + 4*10)*thikness)/2); // RGB
for(int c=0; c<3; c++) {
Imgproc.calcHist(Arrays.asList(mRgba), mChannels[c], mMat0, hist, mHistSize, mRanges);
Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);
hist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++) {
mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
mP1.y = sizeRgba.height-1;
mP2.y = mP1.y - 2 - (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mColorsRGB[c], thikness);
}
}
// Value and Hue
Imgproc.cvtColor(mRgba, mTmp, Imgproc.COLOR_RGB2HSV_FULL);
// Value
Imgproc.calcHist(Arrays.asList(mTmp), mChannels[2], mMat0, hist, mHistSize, mRanges);
Core.normalize(hist, hist, sizeRgba.height/2, 0, Core.NORM_INF);
hist.get(0, 0, mBuff);
for(int h=0; h<mHistSizeNum; h++) {
mP1.x = mP2.x = offset + (3 * (mHistSizeNum + 10) + h) * thikness;
mP1.y = sizeRgba.height-1;
mP2.y = mP1.y - 2 - (int)mBuff[h];
Core.line(mRgba, mP1, mP2, mWhilte, thikness);
}
}
//inner Window Sobel
else if(mProcessMethod==4)
{
Mat gray = inputFrame.gray();
Mat grayInnerWindow = gray.submat(top, top + height, left, left + width);
rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
Imgproc.Sobel(grayInnerWindow, mIntermediateMat, CvType.CV_8U, 1, 1);
Core.convertScaleAbs(mIntermediateMat, mIntermediateMat, 10, 0);
Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);
grayInnerWindow.release();
rgbaInnerWindow.release();
}
//SEPIA
else if(mProcessMethod==5)
{
rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
Core.transform(rgbaInnerWindow, rgbaInnerWindow, mSepiaKernel);
rgbaInnerWindow.release();
}
//ZOOM
else if(mProcessMethod==6)
{
Mat zoomCorner = mRgba.submat(0, rows / 2 - rows / 10, 0, cols / 2 - cols / 10);
Mat mZoomWindow = mRgba.submat(rows / 2 - 9 * rows / 100, rows / 2 + 9 * rows / 100, cols / 2 - 9 * cols / 100, cols / 2 + 9 * cols / 100);
Imgproc.resize(mZoomWindow, zoomCorner, zoomCorner.size());
Size wsize = mZoomWindow.size();
Core.rectangle(mZoomWindow, new Point(1, 1), new Point(wsize.width - 2, wsize.height - 2), new Scalar(255, 0, 0, 255), 2);
zoomCorner.release();
mZoomWindow.release();
}
//PIXELIZE
else if(mProcessMethod==7)
{
rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
Imgproc.resize(rgbaInnerWindow, mIntermediateMat, mSize0, 0.1, 0.1, Imgproc.INTER_NEAREST);
Imgproc.resize(mIntermediateMat, rgbaInnerWindow, rgbaInnerWindow.size(), 0., 0., Imgproc.INTER_NEAREST);
rgbaInnerWindow.release();
}
//POSTERIZE
else if(mProcessMethod==8)
{
rgbaInnerWindow = mRgba.submat(top, top + height, left, left + width);
Imgproc.Canny(rgbaInnerWindow, mIntermediateMat, 80, 90);
rgbaInnerWindow.setTo(new Scalar(0, 0, 0, 255), mIntermediateMat);
Core.convertScaleAbs(rgbaInnerWindow, mIntermediateMat, 1./16, 0);
Core.convertScaleAbs(mIntermediateMat, rgbaInnerWindow, 16, 0);
rgbaInnerWindow.release();
}
else
mRgba = inputFrame.rgba();
return mRgba;
}
}
- 原图
- 灰度图
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuZ3RyZWVz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="400" height="240" alt="">
- Canny边缘检測
- Hist 直方图计算
- Sobel 边缘检測
- SEPIA(色调变换)为每个数组元素运行一个矩阵变换
- ZOOM 放大镜
- PIXELIZE 像素化
- POSTERIZE 多色调分色印
Android学习——在Android中使用OpenCV的第一个程序的更多相关文章
- [置顶] Android学习系列-Android中解析xml(7)
Android学习系列-Android中解析xml(7) 一,概述 1,一个是DOM,它是生成一个树,有了树以后你搜索.查找都可以做. 2,另一种是基于流的,就是解析器从头到尾解析一遍xml文件. ...
- [Android学习笔记]ListView中含有Button导致无法响应onItemClick回调的解决办法
转自:http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html 问题描述: 当ListView的Item中的控件只是一些展示类 ...
- Android学习笔记_49_Android中自定义属性(attrs.xml,TypedArray的使用)
做Android布局是件很享受的事,这得益于他良好的xml方式.使用xml可以快速有效的为软件定义界面.可是有时候我们总感觉官方定义的一些基本组件不够用,自定义组件就不可避免了.那么如何才能做到像官方 ...
- 【Android学习】android:layout_weight的用法实例
对于android:layout_weight的用法,用下面的例子来说明: <LinearLayout xmlns:android="http://schemas.android.co ...
- Android——android学习(android目录与AndroidManifest解析)
res目录:存放android项目的各种资源文件 layout:存放界面布局文件 values:存放各种xml格式的资源文件 strings.xml:字符串资源文件: colors.xml:颜色资源文 ...
- Android学习【Android内核编译流程和错误笔记】
博客:http://blog.csdn.net/muyang_ren Ubuntu14.04 LTS(要求是64位长期支持版LTS) Jdk1.8 内核:android4.0 一:jdk 1.解压jd ...
- Android学习路径——Android的四个组成部分activity(一)
一.什么是Activity? Activity简单的说就是一个接口.我们是Android手机上看到的每个界面就是一个activity. 二.Activity的创建 1.定义一个类继承activity, ...
- Android学习十---Android Camera
Android camera用来拍照和拍摄视频的先看一下最后实现的效果图 最后的效果图 一.准备 在你的应用程序上使用android拍照设备,需要考虑以下几个方面 1. 是否是 ...
- Android 学习之--android多线程断点下载
我们平时都用"迅雷"下载软件,当下载到一半的时候突然断网,下次开启的时候能够从上次下载的地方继续下载,而且下载速度很快,那么这是怎么做到的呢! 其实它的“快”其实就是多线程的下载实 ...
随机推荐
- c# 自动计算字符串的宽度
测试代码: string str = "字符串"; var width = TextRenderer.MeasureText(str, this.Font); var width2 ...
- Spring Boot 自定义属性 以及 乱码问题
自定义属性 使用随机数及自定义配置类 中文乱码问题 1添加配置 2设置文件类型 1IDEA 2eclipse 自定义属性 application.properties提供自定义属性的支持,这样我们就可 ...
- fastjson生成JSON字符串的时候出现$ref
fastjson生成JSON字符串的时候出现$ref 转载自:http://wuzhuti.cn/201426!826!05!130202.html 可以通过选项 DisableCircularRef ...
- Java设计模式(13)模板模式(Template模式)
Template模式定义:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. 其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: pu ...
- [hbase] 查询数据
获取hbase数据 说说:count 'SOCIA:T_SOCIA_ALBUM_TALK'scan 'SOCIA:T_SOCIA_ALBUM_TALK',{LIMIT=>5}get 'SOCIA ...
- backup & restore On Ubuntu
详见:https://help.ubuntu.com/community/BackupYourSystem/TAR 在 使用Ubuntu之前,相信很多人都有过使用Windows系统的经历.如果你备份过 ...
- 关于Unity中的光照(四)
渲染路径和颜色空间 1:Unity光影效果可以通过设置 渲染路径和颜色空间;2: 渲染路径: 光照到物体表面,物体着色的时候,算上光的颜色的时候有这么几种光照的着色方式,计算着色的方式 forward ...
- Opengl绘制我们的小屋(二)第一人称漫游
这章我们先讲第一人称漫游的实现.在openTK里,我们用函数Matrix4.LookAt(caram.Eye,caram.Target,Vector3.UnitY)来放置摄像机,其中三个参数分别与摄像 ...
- 【转】C#解析Json Newtonsoft.Json
Newtonsoft.Json源码 Newtonsoft.Json介绍 在做开发的时候,很多数据交换都是以json格式传输的.而使用Json的时候,我们很多时候会涉及到几个序列化对象的使用:DataC ...
- 第三百九十一节,Django+Xadmin打造上线标准的在线教育平台—404,403,500页面配置
第三百九十一节,Django+Xadmin打造上线标准的在线教育平台—404,403,500页面配置 路由映射在全局也就是根目录里的urls.py里配置404路由映射 注意:不是写在urlpatter ...