2014-01-03 09:24:28 cbacq 阅读数 2012

原文地址:http://www.cnblogs.com/magiccaptain/archive/2013/05/21/3091035.html

 

两个效果:放大和挤压,分别由MaxFrame和MinFrame函数实现, 可直接使用在摄像头中:

 

void MaxFrame(IplImage* frame)
{
    uchar* old_data = (uchar*)frame->imageData;
    uchar* new_data = new uchar[frame->widthStep * frame->height];
    
    int center_X = frame->width / 2;
    int center_Y = frame->height / 2;
    int radius = 400;
    int newX = 0;
    int newY = 0;

    int real_radius = (int)(radius / 2.0);
    for (int i = 0; i < frame->width; i++)
    {
        for (int j = 0; j < frame->height; j++)
        {
            int tX = i - center_X;
            int tY = j - center_Y;

            int distance = (int)(tX * tX + tY * tY);
            if (distance < radius * radius)
            {
                newX = (int)((float)(tX) / 2.0);
                newY = (int)((float)(tY) / 2.0);

                newX = (int) (newX * (sqrt((double)distance) / real_radius));
                newX = (int) (newX * (sqrt((double)distance) / real_radius));

                newX = newX + center_X;
                newY = newY + center_Y;

                new_data[frame->widthStep * j + i * 3] = old_data[frame->widthStep * newY + newX * 3];
                new_data[frame->widthStep * j + i * 3 + 1] =old_data[frame->widthStep * newY + newX * 3 + 1];
                new_data[frame->widthStep * j + i * 3 + 2] =old_data[frame->widthStep * newY + newX * 3 + 2];
            }
            else
            {
                new_data[frame->widthStep * j + i * 3] =  old_data[frame->widthStep * j + i * 3];
                new_data[frame->widthStep * j + i * 3 + 1] =  old_data[frame->widthStep * j + i * 3 + 1];
                new_data[frame->widthStep * j + i * 3 + 2] =  old_data[frame->widthStep * j + i * 3 + 2];
            }
        }
    }
    memcpy(old_data, new_data, sizeof(uchar) * frame->widthStep * frame->height);
    delete new_data;
}


 

void MinFrame(IplImage* frame)
{
    uchar* old_data = (uchar*)frame->imageData;
    uchar* new_data = new uchar[frame->widthStep * frame->height];

    int center_X = frame->width / 2;
    int center_Y = frame->height / 2;

    int radius = 0;
    double theta = 0;
    int newX = 0;
    int newY = 0;

    for (int i = 0; i < frame->width; i++)
    {
        for (int j = 0; j < frame->height; j++)
        {
            int tX = i - center_X;
            int tY = j - center_Y;

            theta = atan2((double)tY, (double)tX);
            radius = (int)sqrt((double)(tX * tX) + (double) (tY * tY));
            int newR = (int)(sqrt((double)radius) * 12);
            newX = center_X + (int)(newR * cos(theta));
            newY = center_Y + (int)(newR * sin(theta));

            if (!(newX > 0 && newX < frame->width))
            {
                newX = 0;
            }
            if (!(newY > 0 && newY < frame->height))
            {
                newY = 0;
            }

            new_data[frame->widthStep * j + i * 3] = old_data[frame->widthStep * newY + newX * 3];
            new_data[frame->widthStep * j + i * 3 + 1] =old_data[frame->widthStep * newY + newX * 3 + 1];
            new_data[frame->widthStep * j + i * 3 + 2] =old_data[frame->widthStep * newY + newX * 3 + 2];
        }
    }
    memcpy(old_data, new_data, sizeof(uchar) * frame->widthStep * frame->height);
    delete new_data;
}


 

2016-05-06 20:06:20 u012590570 阅读数 2458

图像处理的哈哈镜

说起哈哈镜这个东西,好像已经很长时间没有见过了,这曾经在小时候是带来很多乐趣的东西。哈哈镜嘛,无非就是凹面镜或者凸面镜,什么效果呢?凹面镜把人变瘦了,凸面镜把人变胖了。

反映在图像上呢,就是图像的局部的缩放。注意不是整体的放大或缩小,只是一个区域被放大和缩小。为了简单期间,只讨论圆形的区域,因此无非存在两种情况,圆形区域的中心被放大周匝被缩小,或者中心被缩小周匝被放大,而且由中心到周匝的这个缩小放大时逐渐连续变化的(不是突然从缩小变成了放大)。

因此,我们构造了这样一条曲线(以中心缩小,周匝放大为例):
这里写图片描述
这张图上,横坐标是目标图像上的点到圆心的距离,纵坐标是原始图像上的点到圆心的距离,如果是蓝线就是不变换喽,如果是红线呢,会发现比如目标图像上距离圆心30左右的点在原始波形上是距离圆心50左右的点,这个意思很明显了,就是中心区域被缩小了。

至于怎么构造这样一条曲线,这是数学的事,恐怕有很多种办法可以构造。这里说两个必须满足的条件:①红线和蓝线的起点和终点必须是相同的,这个意思是说形变只发生在一个圆形区域内,圆形区域外图像不形变。②曲线的导数必须是连续的,试想一下,如果导数不连续,那么反映在图像上那就是缩小到放大的变化过程不连续了,这里尤其要多说一句,曲线的导数连续,要求在曲线的末端(我这图上是100的位置)导数必须为1。

把这个图上的两个曲线做个除法,就是下面这个结果:
这里写图片描述
这个图实际上说明了一件事,圆心位置的缩放比例是0.5,我们正是根据这个值去构造上面讲的曲线的。

然后剩下的事情就好办了,扫描图像上的点,看看像素是否在圆形区域内(到圆心的距离是不是大于圆的半径),如果不在圆内就原封不动从原始图像上复制过来,如果在圆内,就根据上面的方法找它在原始图像上对应的位置,做插值。

看一下效果,先是原始图像:
这里写图片描述

下面是处理后的图像,所选区域是以狗鼻子为中心的半径为100的圆。下图中中心点的缩放比例依次为:0.5、0.7、0.8、1.2、1.5、2.0
这里写图片描述

是不是很好玩?

我估计小女生们喜欢用美颜相机的瘦脸放大眼睛的功能估计是与此类似的算法。

2015-04-22 12:36:35 Trent1985 阅读数 1466


[函数名称]

  哈哈镜效果函数  WriteableBitmap DistortingMirrorProcess(WriteableBitmap src, int x, int y)

[算法说明]

  哈哈镜效果图像实际上是一种图像形变特效而已,对于这个特效,我们可以通过三角变换来实现。

  1,对于哈哈镜效果变换,首先它有两个参数,原点坐标和特效影响因子。

  对于图像中的像素点P(x,y),假设原点坐标为XY,那么,根据三角函数变换可以得到:

  当前像素P的相对坐标cX,cY:



        /// <summary>
        /// Distorting mirror process.
        /// </summary>
        /// <param name="src">The source image.</param>
        /// <param name="x">Origin of coordinates in x direction.</param>
        /// <param name="y">Origin of coordinates in y direction.</param>
        /// <returns></returns>
         public static WriteableBitmap DistortingMirrorProcess(WriteableBitmap src, int x, int y)////哈哈镜特效
         {
             if (src != null)
             {
                 int w = src.PixelWidth;
                 int h = src.PixelHeight;
                 WriteableBitmap srcImage = new WriteableBitmap(w, h);
                 byte[] temp = src.PixelBuffer.ToArray();
                 byte[] tempMask = (byte[])temp.Clone();
                 int radius = 0;
                 double theta = 0;
                 int tX = 0;
                 int tY = 0;
                 int mapX = 0;
                 int mapY = 0;
                 int mapR=0;
                 for (int j = 0; j < h; j++)
                 {
                     for (int i = 0; i < w; i++)
                     {
                         tX = i - x;
                         tY = j - y;
                         theta = Math.Atan2((double)tY, (double)tX);
                         radius = (int)Math.Sqrt((double)(tX * tX + tY * tY));
                         mapR = (int)(Math.Sqrt((double)radius * 100));
                         mapX = x + (int)(mapR * Math.Cos(theta));
                         mapY = y + (int)(mapR * Math.Sin(theta));
                         temp[i * 4 + j * w * 4] = tempMask[mapX * 4 + mapY * w * 4];
                         temp[i * 4 + 1 + j * w * 4] = tempMask[mapX * 4 + 1 + mapY * w * 4];
                         temp[i * 4 + 2 + j * w * 4] = tempMask[mapX * 4 + 2 + mapY * w * 4];
                     }
                 }
                 Stream sTemp = srcImage.PixelBuffer.AsStream();
                 sTemp.Seek(0, SeekOrigin.Begin);
                 sTemp.Write(temp, 0, w * 4 * h);
                 return srcImage;
             }
             else
             {
                 return null;
             }
         }

[图像效果]




2019-12-10 17:22:34 hide_on_rush 阅读数 20

鬼影特效:

package functions;

import javax.media.*;
import javax.media.Effect;
import javax.media.format.*;
import javax.media.Buffer;
import javax.media.ResourceUnavailableException;

public class NegativeEffect implements Effect {
	private static String EffectName = "NegativeEffect"; // 类名
	protected RGBFormat inputFormat; // 输入的RGB 色彩格式
	protected RGBFormat outputFormat; // 输出的RGB 色彩格式
	protected Format[] supportedInputFormats; // 所有支持的输入格式
	protected Format[] supportedOutputFormats; // 所有支持的输出格式
	// 构造方法,实例化所有支持的输入输出色彩为RGB 色彩格式

	public NegativeEffect() {
		supportedInputFormats = new Format[] { new RGBFormat() };
		supportedOutputFormats = new Format[] { new RGBFormat() };
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输入格式
	public Format[] getSupportedInputFormats() {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getSupportedInputFormats() not yet implemented.");
		System.out.println("getSupportedInputFormats");
		return supportedInputFormats;
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输出格式
	public Format[] getSupportedOutputFormats(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getSupportedOutputFormats() not yet implemented.");
		System.out.println("getSupportedOutputFormats [in = " + parm1 + "]");
		// 如果传入的Format 对象parm1 不是GRBFormat 实例,则返回默认的RGBFormat 格式对象
		if (parm1 == null)
			return supportedOutputFormats;
		if (!(parm1 instanceof RGBFormat))
			return new Format[0];
		// 如果是,根据该格式返回一个对象引用
		RGBFormat irf = (RGBFormat) parm1;
		RGBFormat orf = (RGBFormat) parm1.clone();
		return new Format[] { orf };
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setInputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setInputFormat() not yet implemented.");
		System.out.println("setInputFormat [input = " + parm1 + "]");
		inputFormat = (RGBFormat) parm1;
		return (Format) inputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setOutputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setOutputFormat() not yet implemented.");
		System.out.println("setOutputFormat [ output = " + parm1 + "]");
		outputFormat = (RGBFormat) parm1;
		return (Format) outputFormat;
	}

	// 不一定要实现的两个方法,仅仅满足getXXX,setXXX 的对称性
	public Format getInputFormat() {
		System.out.println("getInputFormat");
		return inputFormat;
	}

	public Format getOutputFormat() {
		System.out.println("getOutputFormat");
		return outputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,处理输入的媒体数据parm1,得到经处理的输出的媒体数据parm2
	// 该方法完成本类的效用,处理媒体数据,达到使色彩反色输出的处理效果
	// 是本类的核心方法
	public int process(Buffer parm1, Buffer parm2) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method process()
		// not yet implemented.");
		Object o1 = parm1.getData(); // 获得输入的数据对象的引用
		int inLength = parm1.getLength(); // 输入的数据的长度
		int inOffset = parm1.getOffset(); // 偏移量
		// 如果输入输出的媒体数据非合法的short[] int[]形式,返回出错信息
		if (!(o1 instanceof short[]) && !(o1 instanceof int[])&& !(o1 instanceof byte[]))
			return this.BUFFER_PROCESSED_FAILED;
		Object o2 = parm2.getData();
		if (o2 != null) {
			if (!(o2 instanceof short[]) && !(o2 instanceof int[])&& !(o1 instanceof byte[]))
				return this.BUFFER_PROCESSED_FAILED;
		} else {
			// 根据输入的数据长度,设置输出的数据长度
			if (o1 instanceof short[])
				parm2.setData(new short[inLength]);
			else if (o1 instanceof int[])
				parm2.setData(new int[inLength]);
			else
				parm2.setData(new byte[inLength]);
			o2 = parm2.getData();
		}
		// 根据输入的数据偏移量,设置输出的数据偏移量
		int outOffset = parm2.getOffset();
		if (o1 instanceof short[]) {
			short[] inData = (short[]) o1;
			short[] outData = (short[]) o2;
			// 处理输入的媒体数据,似的色彩反色,并将数据放入输出的媒体数据对象中
			for (int i = 0; i < inLength; i++)
				outData[outOffset++] = (short) ~inData[inOffset++];
		} else if (o1 instanceof int[]){
			int[] inData = (int[]) o1;
			int[] outData = (int[]) o2;
			for (int i = 0; i < inLength; i++)
				outData[outOffset++] = ~inData[inOffset++];
		}else {
			byte[] inData = (byte[]) o1;
			byte[] outData = (byte[]) o2;
			for (int i = 0; i < inLength; i++)
				outData[outOffset++] = (byte)~inData[inOffset++];
		}
		// 设置输出媒体数据的格式
		parm2.setFormat(outputFormat);
		// 设置输出媒体数据的长度和偏移
		parm2.setLength(inLength);
		parm2.setOffset(0);
		// 返回数据处理成功完成信息
		return this.BUFFER_PROCESSED_OK;
	}

	// 返回类名
	public String getName() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method getName()
		// not yet implemented.");
		System.out.println("getName");
		return EffectName;
	}

	// 以下的方法不一定要求实现,这些方法是Effect 接口的父类的上层类
	// 如javax.media.Controls、javax.media.PlugIn 的方法
	public void open() throws javax.media.ResourceUnavailableException {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method open() not
		// yet implemented.");
		System.out.println("open");
	}

	public void close() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method close() not
		// yet implemented.");
		System.out.println("close");
	}

	public void reset() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method reset() not
		// yet implemented.");
		System.out.println("reset");
	}

	public Object[] getControls() {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControls() not yet implemented.");
		System.out.println("getControls");
		return new Controls[0];
	}

	public Object getControl(String parm1) {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControl() not yet implemented.");
		System.out.println("getControl [controlType = " + parm1 + "]");
		try {
			Class cls = Class.forName(parm1);
			Object[] cs = this.getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i])) {
					return cs[i];
				}
			}
			return null;
		} catch (Exception err) {
			return null;
		}
	}
}

中心内凹特效:

package functions;

import java.awt.Dimension;

import javax.media.*;
import javax.media.format.*;
/**
 * 
 * @author hp
 * 只支持RGB,每个分量用一个8位字节
 * 视频流是byte数组
 */
public class HahajingEffect implements Effect {
	private static String EffectName = "HahajingEffect"; // 类名
	protected RGBFormat inputFormat; // 输入的色彩格式
	protected RGBFormat outputFormat; // 输出的色彩格式
	protected Format[] supportedInputFormats; // 所有支持的输入格式
	protected Format[] supportedOutputFormats; // 所有支持的输出格式
	// 构造方法,实例化所有支持的输入输出色彩为RGB 色彩格式

	public HahajingEffect() {
		supportedInputFormats = new Format[] { new RGBFormat()};
		supportedOutputFormats = new Format[] { new RGBFormat() };
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输入格式
	public Format[] getSupportedInputFormats() {
		return supportedInputFormats;
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输出格式
	public Format[] getSupportedOutputFormats(Format parm1) {
		if (parm1 == null)
			return supportedOutputFormats;
		if (!(parm1 instanceof RGBFormat))
			return new Format[0];
		// 如果是,根据该格式返回一个对象引用
		RGBFormat orf = (RGBFormat) parm1.clone();
		return new Format[] { orf };
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setInputFormat(Format parm1) {
		System.out.println("setInputFormat [input = " + parm1 + "]");
		inputFormat = (RGBFormat) parm1;
		return (Format) inputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setOutputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setOutputFormat() not yet implemented.");
		System.out.println("setOutputFormat [ output = " + parm1 + "]");
		outputFormat = (RGBFormat) parm1;
		return (Format) outputFormat;
	}

	// 不一定要实现的两个方法,仅仅满足getXXX,setXXX 的对称性
	public Format getInputFormat() {
		System.out.println("getInputFormat");
		return inputFormat;
	}

	public Format getOutputFormat() {
		System.out.println("getOutputFormat");
		return outputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,处理输入的媒体数据parm1,得到经处理的输出的媒体数据parm2
	// 该方法完成本类的效用,处理媒体数据,
	// 是本类的核心方法
	public int process(Buffer parm1, Buffer parm2) {
		// this.setInputFormat(parm1.getFormat()); // 设置输入格式
		// this.setOutputFormat(parm1.getFormat());
		// 获取输入格式的视频分辨率
		Dimension size = ((VideoFormat) parm1.getFormat()).getSize();
		int inWidth = size.width;
		int inHeight = size.height;
		Object srcData = parm1.getData(); // 获得输入的数据对象的引用
		// System.out.println(srcData.getClass().toString());
		// 如果输入输出的媒体数据非合法的short[] int[]形式,返回出错信息
		if (!(srcData instanceof byte[]))
			return this.BUFFER_PROCESSED_FAILED;
		Object outputData = null; // parm2.getData();
		if (outputData != null) {
			if (!(srcData instanceof byte[]))
				return this.BUFFER_PROCESSED_FAILED;
		}
		outputData = this.hahajingMirror((byte[]) srcData, 0.0, inWidth, inHeight, inWidth / 2, inHeight / 2);
		
		parm2.setData(outputData);
		int inLength = parm1.getLength(); // 输入的数据的长度
		int inOffset = parm1.getOffset(); // 偏移量
		// 设置输出媒体数据的格式
		parm2.setFormat(parm1.getFormat());
		// 设置输出媒体数据的长度和偏移
		parm2.setLength(inLength);
		parm2.setOffset(inOffset);
		// 返回数据处理成功完成信息
		return this.BUFFER_PROCESSED_OK;
	}

	// 返回类名
	public String getName() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method getName()
		// not yet implemented.");
		System.out.println("getName");
		return EffectName;
	}

	// 以下的方法不一定要求实现,这些方法是Effect 接口的父类的上层类
	// 如javax.media.Controls、javax.media.PlugIn 的方法
	public void open() throws javax.media.ResourceUnavailableException {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method open() not
		// yet implemented.");
		System.out.println("open");
	}

	public void close() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method close() not
		// yet implemented.");
		System.out.println("close");
	}

	public void reset() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method reset() not
		// yet implemented.");
		System.out.println("reset");
	}

	public Object[] getControls() {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControls() not yet implemented.");
		System.out.println("getControls");
		return new Controls[0];
	}

	public Object getControl(String parm1) {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControl() not yet implemented.");
		System.out.println("getControl [controlType = " + parm1 + "]");
		try {
			Class cls = Class.forName(parm1);
			Object[] cs = this.getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i])) {
					return cs[i];
				}
			}
			return null;
		} catch (Exception err) {
			return null;
		}
	}

	private byte[] hahajingMirror(byte[] srcData, double factor, int w, int h, int x, int y) {
		int cenX = x;
		int cenY = y;
		int newX = 0;//新坐标
		int newY = 0;
		int offsetX = 0;
		int offsetY = 0;
		int radius = 0;
		double theta = 0;
		byte[] tempData = (byte[]) srcData.clone();
		int length = srcData.length;
		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w; i++) {
				int tX = i - cenX;
				int tY = j - cenY;
				theta = Math.atan2((double) tY, (double) tX);
				radius = (int) Math.sqrt((double) (tX * tX + tY * tY));
				int newR = (int) (Math.sqrt((double) radius) * 12);
				newX = cenX + (int) (newR * Math.cos(theta));
				newY = cenY + (int) (newR * Math.sin(theta));
				if (newX > 0 && newX < w) {
					offsetX = newX;
				} else {
					newX = 0;
				}
				if (newY > 0 && newY < h) {
					offsetY = newY;
				} else {
					newY = 0;
				}
				int tempLocation1 = i * 3 + j * w * 3;
				int tempLocation2 = i * 3 + 1 + j * w * 3;
				int tempLocation3 = i * 3 + 2 + j * w * 3;
				int srcLocation1 = newX * 3 + newY * w * 3;
				int srcLocation2 = newX * 3 + 1 + newY * w * 3;
				int srcLocation3 = newX * 3 + 2 + newY * w * 3;
				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
					tempData[tempLocation1] = srcData[srcLocation1];
					tempData[tempLocation2] = srcData[srcLocation2];
					tempData[tempLocation3] = srcData[srcLocation3];
				}
			}
		}

		return tempData;

	}
	
}

 

纵向拉长特效:

package functions;
import java.awt.Dimension;

import javax.media.*;
import javax.media.format.*;
/**
 * 
 * @author hp
 * 只支持RGB,每个分量用一个8位字节
 * 视频流是byte数组
 */
public class HahajingEffect2 implements Effect  {

	private static String EffectName = "HahajingEffect"; // 类名
	protected RGBFormat inputFormat; // 输入的色彩格式
	protected RGBFormat outputFormat; // 输出的色彩格式
	protected Format[] supportedInputFormats; // 所有支持的输入格式
	protected Format[] supportedOutputFormats; // 所有支持的输出格式
	// 构造方法,实例化所有支持的输入输出色彩为RGB 色彩格式

	public HahajingEffect2() {
		supportedInputFormats = new Format[] { new RGBFormat()};
		supportedOutputFormats = new Format[] { new RGBFormat() };
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输入格式
	public Format[] getSupportedInputFormats() {
		return supportedInputFormats;
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输出格式
	public Format[] getSupportedOutputFormats(Format parm1) {
		if (parm1 == null)
			return supportedOutputFormats;
		if (!(parm1 instanceof RGBFormat))
			return new Format[0];
		// 如果是,根据该格式返回一个对象引用
		RGBFormat orf = (RGBFormat) parm1.clone();
		return new Format[] { orf };
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setInputFormat(Format parm1) {
		System.out.println("setInputFormat [input = " + parm1 + "]");
		inputFormat = (RGBFormat) parm1;
		return (Format) inputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setOutputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setOutputFormat() not yet implemented.");
		System.out.println("setOutputFormat [ output = " + parm1 + "]");
		outputFormat = (RGBFormat) parm1;
		return (Format) outputFormat;
	}

	// 不一定要实现的两个方法,仅仅满足getXXX,setXXX 的对称性
	public Format getInputFormat() {
		System.out.println("getInputFormat");
		return inputFormat;
	}

	public Format getOutputFormat() {
		System.out.println("getOutputFormat");
		return outputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,处理输入的媒体数据parm1,得到经处理的输出的媒体数据parm2
	// 该方法完成本类的效用,处理媒体数据,
	// 是本类的核心方法
	public int process(Buffer parm1, Buffer parm2) {
		// this.setInputFormat(parm1.getFormat()); // 设置输入格式
		// this.setOutputFormat(parm1.getFormat());
		// 获取输入格式的视频分辨率
		Dimension size = ((VideoFormat) parm1.getFormat()).getSize();
		int inWidth = size.width;
		int inHeight = size.height;
		Object srcData = parm1.getData(); // 获得输入的数据对象的引用
		// System.out.println(srcData.getClass().toString());
		// 如果输入输出的媒体数据非合法的short[] int[]形式,返回出错信息
		if (!(srcData instanceof byte[]))
			return this.BUFFER_PROCESSED_FAILED;
		Object outputData = null; // parm2.getData();
		if (outputData != null) {
			if (!(srcData instanceof byte[]))
				return this.BUFFER_PROCESSED_FAILED;
		}
		outputData = this.hahajingMirror((byte[]) srcData, inWidth, inHeight);
		
		parm2.setData(outputData);
		int inLength = parm1.getLength(); // 输入的数据的长度
		int inOffset = parm1.getOffset(); // 偏移量
		// 设置输出媒体数据的格式
		parm2.setFormat(parm1.getFormat());
		// 设置输出媒体数据的长度和偏移
		parm2.setLength(inLength);
		parm2.setOffset(inOffset);
		// 返回数据处理成功完成信息
		return this.BUFFER_PROCESSED_OK;
	}

	// 返回类名
	public String getName() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method getName()
		// not yet implemented.");
		System.out.println("getName");
		return EffectName;
	}

	// 以下的方法不一定要求实现,这些方法是Effect 接口的父类的上层类
	// 如javax.media.Controls、javax.media.PlugIn 的方法
	public void open() throws javax.media.ResourceUnavailableException {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method open() not
		// yet implemented.");
		System.out.println("open");
	}

	public void close() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method close() not
		// yet implemented.");
		System.out.println("close");
	}

	public void reset() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method reset() not
		// yet implemented.");
		System.out.println("reset");
	}

	public Object[] getControls() {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControls() not yet implemented.");
		System.out.println("getControls");
		return new Controls[0];
	}

	public Object getControl(String parm1) {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControl() not yet implemented.");
		System.out.println("getControl [controlType = " + parm1 + "]");
		try {
			Class cls = Class.forName(parm1);
			Object[] cs = this.getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i])) {
					return cs[i];
				}
			}
			return null;
		} catch (Exception err) {
			return null;
		}
	}

	private byte[] hahajingMirror(byte[] srcData, int w, int h) {
		int oldX = 0;
		int oldY = 0;
		byte[] tempData = (byte[]) srcData.clone();
		int length = srcData.length;
		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w; i++) {
				oldX = i;//x坐标不变
				oldY = j/6;//旧的坐标是新y坐标的1/6
				int tempLocation1 = i * 3 + j * w * 3;
				int tempLocation2 = i * 3 + 1 + j * w * 3;
				int tempLocation3 = i * 3 + 2 + j * w * 3;
				int srcLocation1 = oldX * 3 + oldY * w * 3;
				int srcLocation2 = oldX * 3 + 1 + oldY * w * 3;
				int srcLocation3 = oldX * 3 + 2 + oldY * w * 3;
				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
					tempData[tempLocation1] = srcData[srcLocation1];
					tempData[tempLocation2] = srcData[srcLocation2];
					tempData[tempLocation3] = srcData[srcLocation3];
				}
			}
		}

		return tempData;

	}
}

 

中轴外凸特效:

package functions;

import java.awt.Dimension;

import javax.media.*;
import javax.media.format.*;
/**
 * 
 * @author hp
 * 只支持RGB,每个分量用一个8位字节
 * 视频流是byte数组
 */
public class HahajingEffect3 implements Effect {
	private static String EffectName = "HahajingEffect"; // 类名
	protected RGBFormat inputFormat; // 输入的色彩格式
	protected RGBFormat outputFormat; // 输出的色彩格式
	protected Format[] supportedInputFormats; // 所有支持的输入格式
	protected Format[] supportedOutputFormats; // 所有支持的输出格式
	// 构造方法,实例化所有支持的输入输出色彩为RGB 色彩格式

	public HahajingEffect3() {
		supportedInputFormats = new Format[] { new RGBFormat()};
		supportedOutputFormats = new Format[] { new RGBFormat() };
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输入格式
	public Format[] getSupportedInputFormats() {
		return supportedInputFormats;
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输出格式
	public Format[] getSupportedOutputFormats(Format parm1) {
		if (parm1 == null)
			return supportedOutputFormats;
		if (!(parm1 instanceof RGBFormat))
			return new Format[0];
		// 如果是,根据该格式返回一个对象引用
		RGBFormat orf = (RGBFormat) parm1.clone();
		return new Format[] { orf };
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setInputFormat(Format parm1) {
		System.out.println("setInputFormat [input = " + parm1 + "]");
		inputFormat = (RGBFormat) parm1;
		return (Format) inputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setOutputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setOutputFormat() not yet implemented.");
		System.out.println("setOutputFormat [ output = " + parm1 + "]");
		outputFormat = (RGBFormat) parm1;
		return (Format) outputFormat;
	}

	// 不一定要实现的两个方法,仅仅满足getXXX,setXXX 的对称性
	public Format getInputFormat() {
		System.out.println("getInputFormat");
		return inputFormat;
	}

	public Format getOutputFormat() {
		System.out.println("getOutputFormat");
		return outputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,处理输入的媒体数据parm1,得到经处理的输出的媒体数据parm2
	// 该方法完成本类的效用,处理媒体数据,
	// 是本类的核心方法
	public int process(Buffer parm1, Buffer parm2) {
		// this.setInputFormat(parm1.getFormat()); // 设置输入格式
		// this.setOutputFormat(parm1.getFormat());
		// 获取输入格式的视频分辨率
		Dimension size = ((VideoFormat) parm1.getFormat()).getSize();
		int inWidth = size.width;
		int inHeight = size.height;
		Object srcData = parm1.getData(); // 获得输入的数据对象的引用
		// System.out.println(srcData.getClass().toString());
		// 如果输入输出的媒体数据非合法的short[] int[]形式,返回出错信息
		if (!(srcData instanceof byte[]))
			return this.BUFFER_PROCESSED_FAILED;
		Object outputData = null; // parm2.getData();
		if (outputData != null) {
			if (!(srcData instanceof byte[]))
				return this.BUFFER_PROCESSED_FAILED;
		}
		outputData = this.hahajingMirror((byte[]) srcData, 0.0, inWidth, inHeight, inWidth / 2, inHeight / 2);
		
		parm2.setData(outputData);
		int inLength = parm1.getLength(); // 输入的数据的长度
		int inOffset = parm1.getOffset(); // 偏移量
		// 设置输出媒体数据的格式
		parm2.setFormat(parm1.getFormat());
		// 设置输出媒体数据的长度和偏移
		parm2.setLength(inLength);
		parm2.setOffset(inOffset);
		// 返回数据处理成功完成信息
		return this.BUFFER_PROCESSED_OK;
	}

	// 返回类名
	public String getName() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method getName()
		// not yet implemented.");
		System.out.println("getName");
		return EffectName;
	}

	// 以下的方法不一定要求实现,这些方法是Effect 接口的父类的上层类
	// 如javax.media.Controls、javax.media.PlugIn 的方法
	public void open() throws javax.media.ResourceUnavailableException {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method open() not
		// yet implemented.");
		System.out.println("open");
	}

	public void close() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method close() not
		// yet implemented.");
		System.out.println("close");
	}

	public void reset() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method reset() not
		// yet implemented.");
		System.out.println("reset");
	}

	public Object[] getControls() {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControls() not yet implemented.");
		System.out.println("getControls");
		return new Controls[0];
	}

	public Object getControl(String parm1) {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControl() not yet implemented.");
		System.out.println("getControl [controlType = " + parm1 + "]");
		try {
			Class cls = Class.forName(parm1);
			Object[] cs = this.getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i])) {
					return cs[i];
				}
			}
			return null;
		} catch (Exception err) {
			return null;
		}
	}

	private byte[] hahajingMirror(byte[] srcData, double factor, int w, int h, int x, int y) {
		int cenX = x;
		int cenY = y;
		int newX = 0;
		int newY = 0;
        int R=(int) (Math.sqrt(h*h+w*w)/2);
		int radius = 0;
		byte[] tempData = (byte[]) srcData.clone();
		int length = srcData.length;
		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w; i++) {
				int tX = i - cenX;
				int tY = j - cenY;
				radius = (int) Math.sqrt((double) (tX * tX +tY*tY ));
				if(radius<R) {
					newX=cenX+tX*radius/R;
					 newY=cenY+tY*radius/R;
				}

				int tempLocation1 = i * 3 + j * w * 3;
				int tempLocation2 = i * 3 + 1 + j * w * 3;
				int tempLocation3 = i * 3 + 2 + j * w * 3;
				int srcLocation1 = newX * 3 + newY * w * 3;
				int srcLocation2 = newX * 3 + 1 + newY * w * 3;
				int srcLocation3 = newX * 3 + 2 + newY * w * 3;
				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
					tempData[tempLocation1] = srcData[srcLocation1];
					tempData[tempLocation2] = srcData[srcLocation2];
					tempData[tempLocation3] = srcData[srcLocation3];
				}
			}
		}

		return tempData;

	}
	
}

 

复合特效:

package functions;

import java.awt.Dimension;

import javax.media.*;
import javax.media.format.*;
/**
 * 
 * @author hp
 * 只支持RGB,每个分量用一个8位字节
 * 视频流是byte数组
 */
public class HahajingEffect4 implements Effect {
	private static String EffectName = "HahajingEffect"; // 类名
	protected RGBFormat inputFormat; // 输入的色彩格式
	protected RGBFormat outputFormat; // 输出的色彩格式
	protected Format[] supportedInputFormats; // 所有支持的输入格式
	protected Format[] supportedOutputFormats; // 所有支持的输出格式
	// 构造方法,实例化所有支持的输入输出色彩为RGB 色彩格式

	public HahajingEffect4() {
		supportedInputFormats = new Format[] { new RGBFormat()};
		supportedOutputFormats = new Format[] { new RGBFormat() };
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输入格式
	public Format[] getSupportedInputFormats() {
		return supportedInputFormats;
	}

	// 实现Effect 接口继承自Codec 的方法,返回所有支持的输出格式
	public Format[] getSupportedOutputFormats(Format parm1) {
		if (parm1 == null)
			return supportedOutputFormats;
		if (!(parm1 instanceof RGBFormat))
			return new Format[0];
		// 如果是,根据该格式返回一个对象引用
		RGBFormat orf = (RGBFormat) parm1.clone();
		return new Format[] { orf };
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setInputFormat(Format parm1) {
		System.out.println("setInputFormat [input = " + parm1 + "]");
		inputFormat = (RGBFormat) parm1;
		return (Format) inputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,返回传入的数据格式
	public Format setOutputFormat(Format parm1) {
		/** @todo Implement this javax.media.Codec method */
		// throw new java.lang.UnsupportedOperationException("Method
		// setOutputFormat() not yet implemented.");
		System.out.println("setOutputFormat [ output = " + parm1 + "]");
		outputFormat = (RGBFormat) parm1;
		return (Format) outputFormat;
	}

	// 不一定要实现的两个方法,仅仅满足getXXX,setXXX 的对称性
	public Format getInputFormat() {
		System.out.println("getInputFormat");
		return inputFormat;
	}

	public Format getOutputFormat() {
		System.out.println("getOutputFormat");
		return outputFormat;
	}

	// 实现Effect 接口继承自Codec 的方法,处理输入的媒体数据parm1,得到经处理的输出的媒体数据parm2
	// 该方法完成本类的效用,处理媒体数据,
	// 是本类的核心方法
	public int process(Buffer parm1, Buffer parm2) {
		// this.setInputFormat(parm1.getFormat()); // 设置输入格式
		// this.setOutputFormat(parm1.getFormat());
		// 获取输入格式的视频分辨率
		Dimension size = ((VideoFormat) parm1.getFormat()).getSize();
		int inWidth = size.width;
		int inHeight = size.height;
		Object srcData = parm1.getData(); // 获得输入的数据对象的引用
		// System.out.println(srcData.getClass().toString());
		// 如果输入输出的媒体数据非合法的short[] int[]形式,返回出错信息
		if (!(srcData instanceof byte[]))
			return this.BUFFER_PROCESSED_FAILED;
		Object outputData = null; // parm2.getData();
		if (outputData != null) {
			if (!(srcData instanceof byte[]))
				return this.BUFFER_PROCESSED_FAILED;
		}
		outputData = this.hahajingMirror((byte[]) srcData, 0.0, inWidth, inHeight, inWidth / 2, inHeight / 2);
		
		parm2.setData(outputData);
		int inLength = parm1.getLength(); // 输入的数据的长度
		int inOffset = parm1.getOffset(); // 偏移量
		// 设置输出媒体数据的格式
		parm2.setFormat(parm1.getFormat());
		// 设置输出媒体数据的长度和偏移
		parm2.setLength(inLength);
		parm2.setOffset(inOffset);
		// 返回数据处理成功完成信息
		return this.BUFFER_PROCESSED_OK;
	}

	// 返回类名
	public String getName() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method getName()
		// not yet implemented.");
		System.out.println("getName");
		return EffectName;
	}

	// 以下的方法不一定要求实现,这些方法是Effect 接口的父类的上层类
	// 如javax.media.Controls、javax.media.PlugIn 的方法
	public void open() throws javax.media.ResourceUnavailableException {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method open() not
		// yet implemented.");
		System.out.println("open");
	}

	public void close() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method close() not
		// yet implemented.");
		System.out.println("close");
	}

	public void reset() {
		/** @todo Implement this javax.media.PlugIn method */
		// throw new java.lang.UnsupportedOperationException("Method reset() not
		// yet implemented.");
		System.out.println("reset");
	}

	public Object[] getControls() {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControls() not yet implemented.");
		System.out.println("getControls");
		return new Controls[0];
	}

	public Object getControl(String parm1) {
		/** @todo Implement this javax.media.Controls method */
		// throw new java.lang.UnsupportedOperationException("Method
		// getControl() not yet implemented.");
		System.out.println("getControl [controlType = " + parm1 + "]");
		try {
			Class cls = Class.forName(parm1);
			Object[] cs = this.getControls();
			for (int i = 0; i < cs.length; i++) {
				if (cls.isInstance(cs[i])) {
					return cs[i];
				}
			}
			return null;
		} catch (Exception err) {
			return null;
		}
	}

	private byte[] hahajingMirror(byte[] srcData, double factor, int w, int h, int x, int y) {
		int cenX = x;
		int cenY = y;
		int newX = 0;
		int newY = 0;
		int R=(int) (Math.sqrt(h*h+w*w)/2);
		int offsetX = 0;
		int offsetY = 0;
		int radius = 0;
		double theta = 0;
		byte[] tempData = (byte[]) srcData.clone();
		int length = srcData.length;
		for (int j = 0; j < h; j++) {
			for (int i = 0; i < w/2; i++) {
				int tX = i - cenX;
				int tY = j - cenY;
				theta = Math.atan2((double) tY, (double) tX);
				radius = (int) Math.sqrt((double) (tX * tX + tY * tY));
				int newR = (int) (Math.sqrt((double) radius) * 12);
				newX = cenX + (int) (newR * Math.cos(theta));
				newY = cenY + (int) (newR * Math.sin(theta));
				if (newX > 0 && newX < w) {
					offsetX = newX;
				} else {
					newX = 0;
				}
				if (newY > 0 && newY < h) {
					offsetY = newY;
				} else {
					newY = 0;
				}
				int tempLocation1 = i * 3 + j * w * 3;
				int tempLocation2 = i * 3 + 1 + j * w * 3;
				int tempLocation3 = i * 3 + 2 + j * w * 3;
				int srcLocation1 = newX * 3 + newY * w * 3;
				int srcLocation2 = newX * 3 + 1 + newY * w * 3;
				int srcLocation3 = newX * 3 + 2 + newY * w * 3;
				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
					tempData[tempLocation1] = srcData[srcLocation1];
					tempData[tempLocation2] = srcData[srcLocation2];
					tempData[tempLocation3] = srcData[srcLocation3];
				}
			}
		}
		for (int j = 0; j < h; j++) {
			for (int i = w/2; i < w; i++) {
				int tX = i - cenX;
				int tY = j - cenY;
				radius = (int) Math.sqrt((double) (tX * tX +tY*tY ));
				if(radius<R) {
					newX=cenX+tX*radius/R;
					 newY=cenY+tY*radius/R;
				}

				int tempLocation1 = i * 3 + j * w * 3;
				int tempLocation2 = i * 3 + 1 + j * w * 3;
				int tempLocation3 = i * 3 + 2 + j * w * 3;
				int srcLocation1 = newX * 3 + newY * w * 3;
				int srcLocation2 = newX * 3 + 1 + newY * w * 3;
				int srcLocation3 = newX * 3 + 2 + newY * w * 3;
				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
					tempData[tempLocation1] = srcData[srcLocation1];
					tempData[tempLocation2] = srcData[srcLocation2];
					tempData[tempLocation3] = srcData[srcLocation3];
				}
			}
		}

		return tempData;
	}
//	private byte[] hahajingMirror(byte[] srcData, double factor, int w, int h, int x, int y) {
//		int cenX = x;
//		int cenY = y;
//		int newX = 0;
//		int newY = 0;
//        int R=(int) (Math.sqrt(h*h+w*w)/2);
//		int radius = 0;
//		byte[] tempData = (byte[]) srcData.clone();
//		int length = srcData.length;
//		for (int j = 0; j < h; j++) {
//			for (int i = 0; i < w; i++) {
//				int tX = i - cenX;
//				int tY = j - cenY;
//				radius = (int) Math.sqrt((double) (tX * tX +tY*tY ));
//				if(radius<R) {
//					newX=cenX+tX*radius/R;
//					 newY=cenY+tY*radius/R;
//				}
//
//				int tempLocation1 = i * 3 + j * w * 3;
//				int tempLocation2 = i * 3 + 1 + j * w * 3;
//				int tempLocation3 = i * 3 + 2 + j * w * 3;
//				int srcLocation1 = newX * 3 + newY * w * 3;
//				int srcLocation2 = newX * 3 + 1 + newY * w * 3;
//				int srcLocation3 = newX * 3 + 2 + newY * w * 3;
//				if ((tempLocation1 <= length)&& (tempLocation2 <= length) && (tempLocation3 <= length)
//						&& (srcLocation1 <= length) && (srcLocation2 <= length) && (srcLocation3 <= length)) {				
//					tempData[tempLocation1] = srcData[srcLocation1];
//					tempData[tempLocation2] = srcData[srcLocation2];
//					tempData[tempLocation3] = srcData[srcLocation3];
//				}
//			}
//		}
//
//		return tempData;
//
//	}
//	
}

 

由于时间紧,复合特效就简单的把两种特效一边一半显示,感兴趣可以自己修改。

2019-10-08 13:54:18 qq941716942 阅读数 13

想必大家小时候都照过哈哈镜,看到镜子里变瘦变胖的自己是一件非常有趣的事情,而随着科技不断发展的今天,我们已经可以采用技术和算法在图像中实现哈哈镜的效果了,哈哈镜sdk就是集各式各样的哈哈镜特效为一体的软件开发工具包。那么sdk是如何在图像中实现哈哈镜特效的呢?
在这里插入图片描述
通常哈哈镜sdk在开发过程中,反映在图像上就是图像的一个局部缩放,也就是一个区域被放大和缩小并不是整体的放大或缩小。而哈哈镜效果实际上也是通过图像形变来模拟真实的哈哈镜效果,形变是进行一系列的坐标变换,变换的方法不同那么所呈现出的效果也是不同的。部分参考代码如下:

//

        ///

        /// Sunset Filter

        ///

        /// Source image.

        /// The X position of sun.

        /// The Y position of sun.

        /// The radius of sun light.

        /// The result image.

        private Bitmap ConvexFilterProcess(Bitmap srcBitmap, int cenX, int cenY, int radius)

 {

            Bitmap a = new Bitmap(srcBitmap);

            int w = a.Width;

            int h = a.Height;

            double distance = 0.0;

            double dis = 0.0;

            if (radius > cenX || radius > cenY)

            {

                radius = Math.Min(cenX, cenY);

            }

            Bitmap dst = new Bitmap(w, h);

            System.Drawing.Imaging.BitmapData srcData = a.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            System.Drawing.Imaging.BitmapData dstData = dst.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            unsafe

            {

由于哈哈镜特效的实现需要特定的代码和算法才能实现,所以在开发哈哈镜sdk过程中还是需要具备一定实力的。假设哈哈镜sdk接入直播平台,是否还有需要注意的问题呢?
1.需要确保sdk的整体质量问题,在接入sdk后是否能够在前端正常、流畅、稳定的显示。
2.需要了解sdk是否具备一些基础功能,当然具备多元化的特效功能是更好的。
3.需要保证sdk服务商后期会提供一定的售后服务,以防止出现问题没办法及时解决。
在这里插入图片描述
以上就是哈哈镜sdk在图像中实现的原理和选择过程中需要注意的问题,最主要的还是需要在选择sdk时根据自身平台的运营需求和后期的发展方向进行选择。这样一来,不仅可以给用户增添新的特效玩法,还可以给平台带来更大的流量,可谓是一举两得的好方法。不过还是建议大家找专业的哈哈镜sdk服务商,在质量方面也更有保障一些。
声明:以上内容均为作者本人原创,转载需注明作者及原文链接,欢迎转载分享。

没有更多推荐了,返回首页