使用java和opencv开发游戏辅助工具核心技术分享

2023-09-07 167 0

1、引用javacv

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.6</version>
        </dependency>

2、核心工具类

package com.batfpv.mhxy.utils;

import com.batfpv.mhxy.model.Man;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.opencv_core.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.*;
import static org.bytedeco.opencv.global.opencv_imgproc.*;
import static org.bytedeco.opencv.helper.opencv_imgcodecs.cvLoadImage;

/**
 * @Author: 黄小月
 * @Date: 2021/12/10 12:50
 */
public class ToolsUtil {
    // 全局截屏对象
    public static BufferedImage screen;
    // 模板对象
    private static IplImage matchSample;
    // 阈值
    public static double threshold =0.04f;

    // 最大连续运行时长(秒)
    private static int maxSeconds=300*10000;
    // 控制工具
    public static Robot robot;

    // 截屏尺寸
    public static Rectangle rec;
    // 初始化
    static {
        try {
            robot = new Robot();
            Toolkit tk = Toolkit.getDefaultToolkit(); // 获取缺省工具包
            Dimension di = tk.getScreenSize(); // 屏幕尺寸规格
            rec = new Rectangle(0, 0, di.width, di.height);
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }



    public static boolean colorCompared(Color c1,Color c2){
        return abs(c1.getRed()-c2.getRed())<10 && abs(c1.getGreen()-c2.getGreen())<10 && abs(c1.getBlue()-c2.getBlue())<10;
    }

    public static void moveMouseAndClick(Point p){
        CvPoint cp=new CvPoint();
        cp.x(p.x);
        cp.y(p.y);
        moveMouseAndClick(cp,-1);
    }
    public static void moveMouseAndClickCenter(Point p){
        CvPoint cp=new CvPoint();
        cp.x(p.x);
        cp.y(p.y);
        moveMouseAndClick(cp,0);
    }
    /**
     * 移动到坐标点并点击
     * @param pos 0=中央 1=右侧 -1=原始点
     * @throws AWTException
     */
    public static void moveMouseAndClick(CvPoint p,int pos) {
        int x=p.x();
        int y=p.y();
        if(pos==0) {
            x = x + matchSample.width() / 2;
            y=y+matchSample.height()/2;
        } else if(pos==1) {
            x = x + matchSample.width();
            y=y+matchSample.height();
        }
//        System.out.println(x + "," + y);
        int a = 10;
        Random random = new Random();
        x+=random.nextInt(3);
        y+=random.nextInt(3);
        robot.mouseMove(x, y);
        robot.delay(a);
//        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
//        robot.delay(a);
//        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
//        robot.delay(1000);
        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
        a = random.nextInt(20);
        robot.delay(a);
        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
        robot.delay(30);
    }

    public static void mouseWheel(Point p,int wheelAmt){
        CvPoint cp=new CvPoint();
        cp.x(p.x);
        cp.y(p.y);
        mouseWheel(cp,wheelAmt);
    }
    /**
     * 移动到坐标点,并滚动鼠标
     * @param p
     * @param wheelAmt
     */
    public static void mouseWheel(CvPoint p,int wheelAmt){
        // 负是滑轮向上
        robot.mouseMove(p.x(),p.y());
        robot.mouseWheel(wheelAmt);
    }

    /**
     * 启动截屏线程
     */
    public static void startScreenshotThread(){
        new Thread(){
            public void run() {
                int i=0;
                // 限制总的上限,约一个月
                while (i<maxSeconds) {
                    try {
                        screen = ToolsUtil.Screenshot();
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    i++;
                }
            }
        }.start();
    }

    /**
     * 图片匹配
     * @return 匹配到的坐标
     */
    public static java.util.List<CvPoint> templateMatching(IplImage matchSample,BufferedImage screen,int maxNum){
        java.util.List<CvPoint> list =new ArrayList<CvPoint>();
        // 获取屏幕图片
        IplImage source = new IplImage(opencv_core.cvClone(opencv_core.cvIplImage(ToolsUtil.cvtBuffimageToMat(screen))));

        IplImage result = cvCreateImage(cvSize(
                source.width() - matchSample.width() + 1,
                source.height() - matchSample.height() + 1),
                IPL_DEPTH_32F, 1);

        cvZero(result);
        cvMatchTemplate(source, matchSample, result, CV_TM_SQDIFF_NORMED);
        int i=0;
        CvPoint minLoc = new CvPoint();
        int maxVal=255;
        // 最多支持识别
        while (i<maxNum) {
            i++;
            CvPoint p= getNextMinLoc(result,minLoc,maxVal,matchSample.width(),matchSample.height());
            if(null!=p) {
                list.add(p);
                minLoc=p;
            } else {
                break;
            }
        }
        return list;
    }

    public static CvPoint getNextMinLoc(IplImage result, CvPoint minLoc, int maxVaule, int templatW, int templatH)
    {
        // 先将第一个最小值点附近两倍模板宽度和高度的都设置为最大值防止产生干扰
        int startX = minLoc.x() - templatW;
        int startY = minLoc.y() - templatH;
        int endX = minLoc.x() + templatW;
        int endY = minLoc.y() + templatH;
        if(startX < 0 || startY < 0)
        {
            startX = 0;
            startY = 0;
        }
        if(endX > result.width() - 1 || endY > result.height() - 1)
        {
            endX = result.width() - 1;
            endY = result.height() - 1;
        }
        if(startX!=0 && startY!=0) {
            int y, x;
            for (y = startY; y < endY; y++) {
                for (x = startX; x < endX; x++) {
                    cvSetReal2D(result, y, x, maxVaule);
                }
            }
        }
        CvPoint new_maxLoc = new CvPoint();
        CvPoint new_minLoc = new CvPoint();
        double[] minVal = new double[20];
        double[] maxVal = new double[20];
        DoublePointer new_minVal_d = new DoublePointer(minVal);
        DoublePointer new_maxVal_d = new DoublePointer(maxVal);
        cvMinMaxLoc(result, new_minVal_d, new_maxVal_d, new_minLoc, new_maxLoc, null);
//        System.out.println(new_minVal_d.get());
        if (new_minVal_d.get() < threshold) {
            return new_minLoc;
        }
        return null;
    }

    /**
     * 截屏
     * @return
     * @throws AWTException
     * @throws IOException
     */
    public static BufferedImage Screenshot() {
        BufferedImage bi = robot.createScreenCapture(rec);
        File file = new File("/Users/aa/src/main/resources/image/shot.jpg");
//        try {
//            ImageIO.write(bi, "jpg", file);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        System.out.println("ok");
        return bi;
    }

    /**
     * 截屏图片转byte数组
     * @param buffimge 截屏图片
     * @return byte数组
     */
    public static byte[] cvtBuffimageToByte(BufferedImage buffimge) {
        byte[] bufdata = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(buffimge, "png", baos);
            bufdata = baos.toByteArray();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bufdata;
    }

    /**
     * 截屏图片转Mat对象
     * @param im 截屏图片
     * @return Mat对象
     */
    public static Mat cvtBuffimageToMat(BufferedImage im) {
        byte[] pixels = cvtBuffimageToByte(im);
        return opencv_imgcodecs.imdecode(new Mat(pixels), IMREAD_UNCHANGED);
    }
}

最终产品

相关文章

pdfbox将pdf文件转图片时,报错JPEG2000 image的解决方案
Java 获取客户端IP地址代码分享
Snowflake 分布式自增 ID 算法源码分享
OneinStack 服务器镜像文档
Java 微服务入门源码分享
git 常用命令