From 5d03d332be3bdde6ce07688c78370f1e8edccebd Mon Sep 17 00:00:00 2001 From: gaoben Date: Tue, 30 Jul 2024 16:19:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=8C=E9=9D=99=E8=84=89?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=EF=BC=8C=E6=B5=8B=E8=AF=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/shapelight/AdminApplication.java | 30 +- .../shapelight/common/utils/ImageUtils.java | 216 +++++++ .../shapelight/common/utils/ZipExample.java | 107 ++++ .../ten/controller/TenPersonController.java | 552 +++++++++++++++++- .../src/main/resources/application-dev.yml | 2 +- .../commons/engine/natives/Palmlibrary.java | 62 ++ .../commons/engine/sdk/PalmSDK.java | 225 +++++++ .../commons/engine/sdk/SdkImageUtils.java | 151 +++++ .../shapelight/commons/engine/sdk/main.java | 74 ++- .../engine/sdk/palm/FaceFeatureBase.java | 9 + .../engine/sdk/palm/FaceFeatureFloat.java | 36 ++ .../commons/engine/sdk/palm/OutArg.java | 12 + 12 files changed, 1457 insertions(+), 19 deletions(-) create mode 100644 shapelight-admin/src/main/java/net/shapelight/common/utils/ZipExample.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/natives/Palmlibrary.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/PalmSDK.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/SdkImageUtils.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureBase.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureFloat.java create mode 100644 shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/OutArg.java diff --git a/shapelight-admin/src/main/java/net/shapelight/AdminApplication.java b/shapelight-admin/src/main/java/net/shapelight/AdminApplication.java index 60e851f..fb66eb1 100644 --- a/shapelight-admin/src/main/java/net/shapelight/AdminApplication.java +++ b/shapelight-admin/src/main/java/net/shapelight/AdminApplication.java @@ -3,6 +3,8 @@ package net.shapelight; //import net.shapelight.modules.dev.mqtt.MqttClientUtil; +import lombok.extern.slf4j.Slf4j; +import net.shapelight.commons.engine.sdk.PalmSDK; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -12,6 +14,7 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ImportResource; import org.springframework.transaction.annotation.EnableTransactionManagement; +@Slf4j //@ImportResource(value = { "classpath:spring/spring.xml" }) @SpringBootApplication//(exclude = DataSourceAutoConfiguration.class)//排除DataSourceConfiguratrion @EnableCaching @@ -22,21 +25,24 @@ public class AdminApplication { public static void main(String[] args) { SpringApplication.run(AdminApplication.class, args); + + //初始化掌静脉sdk + int initCode = PalmSDK.init(); + log.debug("掌静脉sdk初始化。。。。。。。。。。:"+initCode); // //mqtt服务启动 // MqttClientUtil.createClient(); // -// Runtime.getRuntime().addShutdownHook(new Thread() { -// @Override -// public void run() { -// try { -// //释放工作 -// //... -// -// } catch (Throwable e) { -// e.printStackTrace(); -// } -// } -// }); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + int code = PalmSDK.release(); + log.debug("掌静脉sdk释放。。。。。。。。。。:"+code); + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); } } diff --git a/shapelight-admin/src/main/java/net/shapelight/common/utils/ImageUtils.java b/shapelight-admin/src/main/java/net/shapelight/common/utils/ImageUtils.java index f301c34..021c3d7 100644 --- a/shapelight-admin/src/main/java/net/shapelight/common/utils/ImageUtils.java +++ b/shapelight-admin/src/main/java/net/shapelight/common/utils/ImageUtils.java @@ -1,10 +1,15 @@ package net.shapelight.common.utils; +import org.springframework.web.multipart.MultipartFile; + import javax.imageio.ImageIO; +import javax.imageio.stream.FileImageInputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.Base64; import java.util.Date; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; public class ImageUtils { /** @@ -101,6 +106,127 @@ public class ImageUtils { return out.toByteArray(); } + + //图片到byte数组 + public static byte[] image2byte(String path){ + byte[] data = null; + FileImageInputStream input = null; + try { + input = new FileImageInputStream(new File(path)); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int numBytesRead = 0; + while ((numBytesRead = input.read(buf)) != -1) { + output.write(buf, 0, numBytesRead); + } + data = output.toByteArray(); + output.close(); + input.close(); + } + catch (FileNotFoundException ex1) { + ex1.printStackTrace(); + } + catch (IOException ex1) { + ex1.printStackTrace(); + } + return data; + } + + public static byte[] getNV21(BufferedImage bufferedImage) { +// BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData)); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + int[] pixels = bufferedImage.getRGB(0, 0, width, height, null, 0, width); + byte[] yuvs = encodeYUV420SP(pixels, width, height); + return yuvs; + } + + /** + * nv21  先u后v + * + * @return + * @paramargb + * @paramwidth + * @paramheight + */ + + public static byte[] encodeYUV420SP(int[] argb, int width, int height) { + int size = (int) ((Math.ceil(width / 2.0)) * (Math.ceil(height / 2.0))); + int frameSize = width * height; + byte[] yuvs = new byte[frameSize + size * 2]; + int y = 0, u = 0, v = 0; + int r = 0, g = 0, b = 0, a = 0; + int index = 0, uvindex = frameSize; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + a = (argb[index] & 0xff000000) >> 24;// a is not used obviously + r = (argb[index] & 0xff0000) >> 16; + g = (argb[index] & 0xff00) >> 8; + b = (argb[index] & 0xff) >> 0; +//转换公式 + y = (int) (0.299 * r + 0.587 * g + 0.114 * b); + u = (int) (-0.1687 * r - 0.3313 * g + 0.5 * b + 128); + v = (int) (0.5 * r - 0.4187 * g - 0.0813 * b + 128); +// System.out.println("x:" + i + "y:" + j + "  y:" + y + " u:" + u + " v:" + v); + yuvs[index++] = (byte) ((y < 0) ? 0 : ((y > 255) ? 255 : y)); + if (i % 2 == 0 && j % 2 == 0) { + yuvs[uvindex++] = (byte) ((u < 0) ? 0 : ((u > 255) ? 255 : u)); + yuvs[uvindex++] = (byte) ((v < 0) ? 0 : ((v > 255) ? 255 : v)); +//                    yuvs[uvindex++]=(byte)120; +//                    yuvs[uvindex++] = (byte) ((v < 0) ? 0 : ((v > 255) ? 255 : v)); +//                    yuvs[uvindex++]=(byte)240; + } + } + } + return yuvs; + } + + public static int[] decodeYUV420sp(byte[] yuvs, int width, int height) { + int frameSize = width * height; + int[] rgbs = new int[frameSize]; + int index = 0; + int uvindex = frameSize; + int u = 0, v = 0, y = 0; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (i % 2 == 0 && j % 2 == 0) { + u = yuvs[uvindex++]; + v = yuvs[uvindex++]; + } +//保存到数组中去 + y = yuvs[index]; + rgbs[index++] = yuv2Rgb(y, u, v); + } + } + return rgbs; + } + + public static int yuv2Rgb(int y, int u, int v) { +// 转换公式 + int r = (int) ((y & 0xff) + 1.402 * ((v & 0xff) - 128)); + int g = (int) ((y & 0xff) - 0.34414 * ((u & 0xff) - 128) - 0.71414 * ((v & 0xff) - 128)); + int b = (int) ((y & 0xff) + 1.772 * ((u & 0xff) - 128)); + r = (r < 0 ? 0 : r > 255 ? 255 : r); + g = (g < 0 ? 0 : g > 255 ? 255 : g); + b = (b < 0 ? 0 : b > 255 ? 255 : b); + return (0xff << 24) + (r << 16) + (g << 8) + b; + } + + +// public static void main(String[] args) { +// +//// File imgFile = new File("/home/huangyifang/gb/palm/noface.jpg"); +// String path = "/home/huangyifang/gb/palm/noface.jpg"; +// byte[] imageData = image2byte(path); +// try { +// BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData)); +// byte[] nv21 = getNV21(bufferedImage); +// System.out.println("000000000000000000"); +// }catch (Exception e){ +// e.printStackTrace(); +// } +// } + public static void main(String[] args) throws IOException { // String imageStr = GetImageBase64Str("d:/3.jpg"); // System.out.println(imageStr); @@ -119,4 +245,94 @@ public class ImageUtils { } } + + public static void saveMultiFile(MultipartFile mFile, String destFile) throws Exception{ + InputStream in_left0 = mFile.getInputStream(); + OutputStream os_left0 = new FileOutputStream(destFile); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = in_left0.read(buffer, 0, 8192)) != -1) { + os_left0.write(buffer, 0, bytesRead); + } + os_left0.close(); + in_left0.close(); + } + + + public static void main2(String[] args) { + String zipFileName = "example.zip"; + String folderToCompress = "folder"; + + try ( + ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName))) { + // 压缩文件夹 + compressFolder(folderToCompress, folderToCompress, zipOutputStream); + + System.out.println("Folder compressed successfully!"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void compressFolder(String sourceFolder, String folderName, ZipOutputStream zipOutputStream) throws IOException { + File folder = new File(sourceFolder); + File[] files = folder.listFiles(); + + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + // 压缩子文件夹 + compressFolder(file.getAbsolutePath(), folderName + "/" + file.getName(), zipOutputStream); + } else { + // 压缩文件 + addToZipFile(folderName + "/" + file.getName(), file.getAbsolutePath(), zipOutputStream); + } + } + } + } + + public static void addToZipFile(String fileName, String fileAbsolutePath, ZipOutputStream zipOutputStream) throws IOException { + // 创建ZipEntry对象并设置文件名 + ZipEntry entry = new ZipEntry(fileName); + zipOutputStream.putNextEntry(entry); + + // 读取文件内容并写入Zip文件 + try (FileInputStream fileInputStream = new FileInputStream(fileAbsolutePath)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = fileInputStream.read(buffer)) != -1) { + zipOutputStream.write(buffer, 0, bytesRead); + } + } + // 完成当前文件的压缩 + zipOutputStream.closeEntry(); + } + + public static void createDir(String dir){ + File folder = new File(dir); + // 判断文件夹是否存在 + if (!folder.exists()) { + // 创建文件夹 + boolean result = folder.mkdirs(); + if (result) { + System.out.println("文件夹创建成功"); + } else { + System.out.println("文件夹创建失败"); + } + } else { + System.out.println("文件夹已存在"); + } + } + + public static void deleteFolder(File folder) { + if (folder.isDirectory()) { + File[] files = folder.listFiles(); + if (files != null) { + for (File file : files) { + deleteFolder(file); + } + } + } + folder.delete(); + } } diff --git a/shapelight-admin/src/main/java/net/shapelight/common/utils/ZipExample.java b/shapelight-admin/src/main/java/net/shapelight/common/utils/ZipExample.java new file mode 100644 index 0000000..0ec8a71 --- /dev/null +++ b/shapelight-admin/src/main/java/net/shapelight/common/utils/ZipExample.java @@ -0,0 +1,107 @@ +package net.shapelight.common.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipExample { +// public static void main(String[] args) { +// String zipFileName = "/home/huangyifang/gb/palm/temp/20323/example.zip"; +// String folderToCompress = "/home/huangyifang/gb/palm/temp/20323"; +// +// try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFileName))) { +// // 压缩文件夹 +// compressFolder(folderToCompress, folderToCompress, zipOutputStream); +// +// System.out.println("Folder compressed successfully!"); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// +// private static void compressFolder(String sourceFolder, String folderName, ZipOutputStream zipOutputStream) throws IOException { +// File folder = new File(sourceFolder); +// File[] files = folder.listFiles(); +// +// if (files != null) { +// for (File file : files) { +// if (file.isDirectory()) { +// // 压缩子文件夹 +// compressFolder(file.getAbsolutePath(), folderName + "/" + file.getName(), zipOutputStream); +// } else { +// // 压缩文件 +// addToZipFile(folderName + "/" + file.getName(), file.getAbsolutePath(), zipOutputStream); +// } +// } +// } +// } +// +// private static void addToZipFile(String fileName, String fileAbsolutePath, ZipOutputStream zipOutputStream) throws IOException { +// // 创建ZipEntry对象并设置文件名 +// ZipEntry entry = new ZipEntry(fileName); +// zipOutputStream.putNextEntry(entry); +// +// // 读取文件内容并写入Zip文件 +// try (FileInputStream fileInputStream = new FileInputStream(fileAbsolutePath)) { +// byte[] buffer = new byte[1024]; +// int bytesRead; +// while ((bytesRead = fileInputStream.read(buffer)) != -1) { +// zipOutputStream.write(buffer, 0, bytesRead); +// } +// } +// +// // 完成当前文件的压缩 +// zipOutputStream.closeEntry(); +// } + + public static void main(String[] args) { + // 要压缩的文件或文件夹 + String sourceFile = "/home/huangyifang/project/cell/temp/b68fa15aa7c146f6aa453475981f0b7e"; + + // 压缩后的ZIP文件名 + String zipFileName = "/home/huangyifang/project/cell/temp/b68fa15aa7c146f6aa453475981f0b7e.zip"; + + // 创建一个输出流将数据写入ZIP文件 + try (FileOutputStream fos = new FileOutputStream(zipFileName); + ZipOutputStream zos = new ZipOutputStream(fos)) { + + // 调用递归方法压缩文件或文件夹 + addToZipFile(sourceFile, sourceFile, zos); + + System.out.println("文件已成功打包成 " + zipFileName); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void addToZipFile(String path, String sourceFile, ZipOutputStream zos) throws IOException { + File file = new File(sourceFile); + + // 如果是文件夹,则获取其内容并递归调用此方法 + if (file.isDirectory()) { + String[] fileList = file.list(); + if (fileList != null) { + for (String fileName : fileList) { + addToZipFile(path, sourceFile + File.separator + fileName, zos); + } + } + return; + } + + // 如果是文件,则将其添加到ZIP文件中 + try (FileInputStream fis = new FileInputStream(sourceFile)) { + String entryName = sourceFile.substring(path.length() + 1); // 获取ZIP中的条目名称 + ZipEntry zipEntry = new ZipEntry(entryName); + zos.putNextEntry(zipEntry); + + byte[] bytes = new byte[1024]; + int length; + while ((length = fis.read(bytes)) >= 0) { + zos.write(bytes, 0, length); + } + } + } +} diff --git a/shapelight-admin/src/main/java/net/shapelight/modules/ten/controller/TenPersonController.java b/shapelight-admin/src/main/java/net/shapelight/modules/ten/controller/TenPersonController.java index dbfe2aa..d367190 100644 --- a/shapelight-admin/src/main/java/net/shapelight/modules/ten/controller/TenPersonController.java +++ b/shapelight-admin/src/main/java/net/shapelight/modules/ten/controller/TenPersonController.java @@ -1,9 +1,9 @@ package net.shapelight.modules.ten.controller; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; +import java.awt.image.BufferedImage; +import java.io.*; import java.util.*; +import java.util.zip.ZipOutputStream; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.minio.MinioClient; @@ -16,7 +16,11 @@ import lombok.extern.slf4j.Slf4j; import net.shapelight.common.config.GlobalValue; import net.shapelight.common.config.MinioConfig; import net.shapelight.common.utils.*; +import net.shapelight.commons.engine.sdk.PalmSDK; import net.shapelight.commons.engine.sdk.PicSDK; +import net.shapelight.commons.engine.sdk.SdkImageUtils; +import net.shapelight.commons.engine.sdk.palm.FaceFeatureBase; +import net.shapelight.commons.engine.sdk.palm.OutArg; import net.shapelight.modules.app.entity.AppUserEntity; import net.shapelight.modules.app.service.AppUserService; import net.shapelight.modules.excel.model.PersonModel; @@ -37,6 +41,8 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; + /** * 人员表 @@ -766,7 +772,547 @@ public class TenPersonController extends AbstractController { } return R.ok("成功上传"+(list.size()-failCount)+"条数据,"+failCount+"条数据上传失败").put("data",listError); } catch (Exception e) { + log.error(e.getMessage()); return R.error(e.getMessage()); } } + + + @PostMapping("/palmCheck") + @ApiOperation("掌静脉检测") + public R palmCheck(@RequestParam("file") MultipartFile file) { + if (file.isEmpty() || file.getSize() == 0) { + return R.error("文件不能为空"); + } + int regRes = 0; + try { + String uuid = UUIDUtil.uuid(); + //文件夹 + String tempFile = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid+".jpg"; + File dest = new File(tempFile); +// file.transferTo(dest); + + InputStream ins = file.getInputStream(); + OutputStream os = new FileOutputStream(dest); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + ins.close(); + + + BufferedImage bufferedImage= ImageIO.read(file.getInputStream()); + byte[] nv21 = SdkImageUtils.getNV21(bufferedImage); + OutArg feature = new OutArg<>(); + regRes = PalmSDK.PushIrAndRegister(bufferedImage.getWidth(),bufferedImage.getHeight(),nv21,feature); + log.debug("检测结果:"+regRes); + //删除临时文件 + dest.delete(); + if(regRes == 0) { + return R.ok(); + }else if(regRes == -21){ + return R.error("距离太近,错误码:"+regRes); + }else if(regRes == -22){ + return R.error("距离太远,错误码:"+regRes); + }else if(regRes == -23){ + return R.error("过曝丢弃,错误码:"+regRes); + }else if(regRes == -24){ + return R.error("未检测到手掌,错误码:"+regRes); + }else if(regRes == -33){ + return R.error("提取ROI图像失败,错误码:"+regRes); + }else{ + return R.error("检测失败,错误码:"+regRes); + } + } catch (Exception e) { + log.error(e.getMessage()); + return R.error("Exception Error,错误码:"+regRes); + } + } + + + + + @PostMapping("/updatePalm") + @RequiresPermissions("ten:person") + @ApiOperation(value = "修改人员信息") + public R updatePalm(@RequestPart(value = "tenPerson") TenPersonEntity tenPerson, + @RequestPart(value = "left_ir0",required = false) MultipartFile left_ir0, + @RequestPart(value = "left_ir1",required = false) MultipartFile left_ir1, + @RequestPart(value = "left_ir2",required = false) MultipartFile left_ir2, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir0, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir1, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir2 + ) { + tenPerson.setTenantId(getUser().getTenantId()); + tenPerson.setLastUpdateBy(getUser().getUsername()); + tenPerson.setLastUpdateTime(new Date()); + tenPerson.setFaceFailure(Constant.FACE_FAILURE_OK); + + if(tenPerson.getIdCard()!=null){ + if(tenPerson.getIdCard().length() == 15){ + String id18 = Convert.toEighteen(tenPerson.getIdCard()); + tenPerson.setIdCard(id18); + } + } + + if(tenPerson.getName()!=null){ + TenPersonEntity oldPerson = tenPersonService.getById(tenPerson.getPersonId(),tenPerson.getCellId()); + if(!tenPerson.getName().equals(oldPerson.getName())){ + TenPersonEntity tenPersonEntity = tenPersonService.findByName(tenPerson.getName(), + oldPerson.getRoomId(),oldPerson.getCellId()); + if(tenPersonEntity!=null){ + return R.error("姓名在此房间已存在"); + } + } + } + + if(tenPerson.getIdCard()!=null){ + TenPersonEntity oldPerson = tenPersonService.getById(tenPerson.getPersonId(),tenPerson.getCellId()); + if(!tenPerson.getIdCard().equals(oldPerson.getIdCard())){ + List list = tenPersonService.findByIdCardAndDept(tenPerson.getIdCard(),oldPerson.getDeptId()); + if(list.size()>0){ + return R.error("身份证在此组织已存在"); + } + } + } + + //验证卡号 + if(tenPerson.getDoorCardEntity()!=null && tenPerson.getDoorCardEntity().getDoorCard()!=null + && !tenPerson.getDoorCardEntity().getDoorCard().isEmpty()){ + + TenDoorCardEntity oldDoorCard = tenDoorCardService.getOne(new QueryWrapper() + .eq("person_id",tenPerson.getPersonId())); + if (oldDoorCard!=null) { + if(oldDoorCard.getDoorCard().equals(tenPerson.getDoorCardEntity().getDoorCard())){ + + }else{ + TenDoorCardEntity card = tenDoorCardService.getOne(new QueryWrapper() + .eq("door_card",tenPerson.getDoorCardEntity().getDoorCard()) + .eq("cell_id",tenPerson.getCellId())); + if(card!=null){ + return R.error("卡号已录入"); + } + } + }else{ + TenDoorCardEntity card = tenDoorCardService.getOne(new QueryWrapper() + .eq("door_card",tenPerson.getDoorCardEntity().getDoorCard()) + .eq("cell_id",tenPerson.getCellId())); + if(card!=null){ + return R.error("卡号已录入"); + } + } + } + else if(tenPerson.getDoorCardEntity()!=null && tenPerson.getDoorCardEntity().getDoorCard()!=null + && tenPerson.getDoorCardEntity().getDoorCard().trim().equals("")){ + } + else{ + tenPerson.setDoorCardEntity(null); + } + + //----------------------------------掌静脉特征压缩包封装-------------------------------------- + if (left_ir0!=null && !left_ir0.isEmpty() + && left_ir1!=null && !left_ir1.isEmpty() + && left_ir2!=null && !left_ir2.isEmpty() + && right_ir0!=null && !right_ir0.isEmpty() + && right_ir1!=null && !right_ir1.isEmpty() + && right_ir2!=null && !right_ir2.isEmpty()){ + + String uuid = UUIDUtil.uuid(); + //文件夹 + String tempDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid; + ImageUtils.createDir(tempDir); + //left文件夹 + String leftDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid+"/left"; + ImageUtils.createDir(leftDir); + //right文件夹 + String rightDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid+"/right"; + ImageUtils.createDir(rightDir); + //zip文件 +// File zipFile = new File(globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+".zip"); + String zipFile = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+".zip"; + //rgb文件 + String rgbFile = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+"/rgb.jpg"; + +// File left_ir0_file = new File(tempDir+"/left_ir0.jpg"); +// File left_ir1_file = new File(tempDir+"/left_ir1.jpg"); +// File left_ir2_file = new File(tempDir+"/left_ir2.jpg"); +// File right_ir0_file = new File(tempDir+"/right_ir0.jpg"); +// File right_ir1_file = new File(tempDir+"/right_ir1.jpg"); +// File right_ir2_file = new File(tempDir+"/right_ir2.jpg"); + + //保存rgb + String tempOrgImageFile = tenPerson.getOrgImageTemp(); + if (tempOrgImageFile != null && !tempOrgImageFile.isEmpty()) { + try { + // 调用statObject()来判断对象是否存在。 + // 如果不存在, statObject()抛出异常, + // 否则则代表对象存在。 + minioClient.statObject(minioConfig.getBucketName(), tempOrgImageFile); + + //判断人脸照片是否合格 + //1.保存到本地 + InputStream tempInputStream = minioClient.getObject(minioConfig.getBucketName(), tempOrgImageFile); +// String tempPath = globalValue.getStaticLocations() + "/";//+globalValue.getTempDir()+"/"; +// String tempOrgFilePath = tempPath + tempOrgImageFile; + int index; + byte[] bytes = new byte[1024]; + File outFile = new File(rgbFile); + FileOutputStream downloadFile = new FileOutputStream(outFile); + while ((index = tempInputStream.read(bytes)) != -1) { + downloadFile.write(bytes, 0, index); + downloadFile.flush(); + } + downloadFile.close(); + tempInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }else if(tenPerson.getOrgImage()!=null && !tenPerson.getOrgImage().isEmpty()){ + try { + // 调用statObject()来判断对象是否存在。 + // 如果不存在, statObject()抛出异常, + // 否则则代表对象存在。 + minioClient.statObject(minioConfig.getBucketName(), tenPerson.getOrgImage()); + + //判断人脸照片是否合格 + //1.保存到本地 + InputStream tempInputStream = minioClient.getObject(minioConfig.getBucketName(), tenPerson.getOrgImage()); +// String tempPath = globalValue.getStaticLocations() + "/";//+globalValue.getTempDir()+"/"; +// String tempOrgFilePath = tempPath + tempOrgImageFile; + int index; + byte[] bytes = new byte[1024]; + File outFile = new File(rgbFile); + FileOutputStream downloadFile = new FileOutputStream(outFile); + while ((index = tempInputStream.read(bytes)) != -1) { + downloadFile.write(bytes, 0, index); + downloadFile.flush(); + } + downloadFile.close(); + tempInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + try{ + ImageUtils.saveMultiFile(left_ir0, leftDir+"/ir0.jpg"); + ImageUtils.saveMultiFile(left_ir1, leftDir+"/ir1.jpg"); + ImageUtils.saveMultiFile(left_ir2, leftDir+"/ir2.jpg"); + ImageUtils.saveMultiFile(right_ir0, rightDir+"/ir0.jpg"); + ImageUtils.saveMultiFile(right_ir1, rightDir+"/ir1.jpg"); + ImageUtils.saveMultiFile(right_ir2, rightDir+"/ir2.jpg"); + }catch (Exception e){ + e.printStackTrace(); + } + + // 要压缩的文件或文件夹 + String sourceFile = tempDir; + // 压缩后的ZIP文件名 + String zipFileName = zipFile; + // 创建一个输出流将数据写入ZIP文件 + try { + FileOutputStream fos = new FileOutputStream(zipFileName); + ZipOutputStream zos = new ZipOutputStream(fos); + // 调用递归方法压缩文件或文件夹 + ZipExample.addToZipFile(sourceFile, sourceFile, zos); + System.out.println("文件已成功打包成 " + zipFileName); + zos.close(); + fos.close(); + }catch (Exception e){ + e.printStackTrace(); + } + + //保存minio' + try { +// String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //后缀名 + String userFileUrl = globalValue.getImagesDir() + "/" + + tenPerson.getCellId().toString() + "/" + + tenPerson.getPersonId().toString() + "/"; + String fileName = userFileUrl + "p_" + uuid + ".zip"; + InputStream inputStream = new FileInputStream(zipFile); + PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1); + putObjectOptions.setContentType("application/zip"); + minioClient.putObject( + minioConfig.getBucketName(), fileName, inputStream, putObjectOptions); + inputStream.close(); + //删除zip文件: + File delZip = new File(zipFile); + delZip.delete(); + //删除临时文件夹 + ImageUtils.deleteFolder(new File(tempDir)); + //删除临时rgb文件 + File rgbFileTemp = new File(rgbFile); + rgbFileTemp.delete(); + + tenPerson.setSourceFile(fileName); + } catch (Exception e) { + } + } + + //----------------------------------掌静脉特征压缩包封装-------------------------------------- + + String resStr = tenPersonService.updateById(tenPerson); + if(resStr.equals("OK")){ + return R.ok(); + }else{ + return R.error(resStr); + } + } + + + /** + * 保存 + */ + @PostMapping("/savePalm") + @RequiresPermissions("ten:person") + @ApiOperation(value = "保存人员信息") + public R savePalm(@RequestPart(value = "tenPerson") TenPersonEntity tenPerson, + @RequestPart(value = "left_ir0",required = false) MultipartFile left_ir0, + @RequestPart(value = "left_ir1",required = false) MultipartFile left_ir1, + @RequestPart(value = "left_ir2",required = false) MultipartFile left_ir2, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir0, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir1, + @RequestPart(value = "right_ir0",required = false) MultipartFile right_ir2 + ) { +// TenPersonEntity room = tenPersonService.queryByNumberAndLayer(tenRoom.getRoomNumber(), +// tenRoom.getLayer(), +// tenRoom.getBuildId(), +// tenRoom.getCellId()); +// if(room!=null){ +// return R.error("此户室已经存在"); +// } + if(tenPerson.getIdCard()!=null){ + if(tenPerson.getIdCard().length() == 15){ + String id18 = Convert.toEighteen(tenPerson.getIdCard()); + tenPerson.setIdCard(id18); + } + } + //验证app人员是否注册 + if (tenPerson.getAppFlag() == Constant.APP_LOGIN_YES) { + //1.验证用户名 + AppUserEntity appUser = appUserService.findByUsername(tenPerson.getUsername()); +// if (appUser != null) { +// return R.error("用户名已经注册"); +// } + //2.验证手机号 + appUser = appUserService.findByMobile(tenPerson.getMobile()); + if (appUser != null) { + return R.error("手机号已经注册"); + } + } + //验证卡号 + if(tenPerson.getDoorCardEntity()!=null && tenPerson.getDoorCardEntity().getDoorCard().isEmpty()){ + //1. 检查当前钥匙是否已经使用 + TenDoorCardEntity card = tenDoorCardService.getOne(new QueryWrapper() + .eq("door_card",tenPerson.getDoorCardEntity().getDoorCard()) + .eq("cell_id",tenPerson.getCellId())); + if(card!=null){ + return R.error("卡号已录入"); + } +// tenDoorCardService.save(tenPerson); + } + + + TenPersonEntity tenPersonEntity = tenPersonService.findByName(tenPerson.getName(), + tenPerson.getRoomId(),tenPerson.getCellId()); + if(tenPersonEntity!=null){ + return R.error("姓名在此房间已存在"); + } + + + if(tenPerson.getIdCard()!=null){ +// TenPersonEntity tenPersonIdcard = tenPersonService.findByIdCard(tenPerson.getIdCard(), +// tenPerson.getRoomId(),tenPerson.getCellId()); +// if(tenPersonIdcard!=null){ +// return R.error("身份证在此房间已存在"); +// } + List list = tenPersonService.findByIdCardAndDept(tenPerson.getIdCard(),tenPerson.getDeptId()); + if(list.size()>0){ + return R.error("身份证在此组织已存在"); + } + + } + + + long id = new SnowflakeIdWorker().nextId(); + tenPerson.setPersonId(id); + tenPerson.setUuid(UUIDUtil.uuid()); + tenPerson.setTenantId(getUser().getTenantId()); + tenPerson.setCreateBy(getUser().getUsername()); + tenPerson.setCreateTime(new Date()); + tenPerson.setRegisterType(Constant.RESGISTER_TYPE_WEB); + tenPerson.setStatus(Constant.PESON_SUATUS_NOMOR); + + + + //----------------------------------掌静脉特征压缩包封装-------------------------------------- + if (left_ir0!=null && !left_ir0.isEmpty() + && left_ir1!=null && !left_ir1.isEmpty() + && left_ir2!=null && !left_ir2.isEmpty() + && right_ir0!=null && !right_ir0.isEmpty() + && right_ir1!=null && !right_ir1.isEmpty() + && right_ir2!=null && !right_ir2.isEmpty()){ + + String uuid = UUIDUtil.uuid(); + //文件夹 + String tempDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid; + ImageUtils.createDir(tempDir); + //left文件夹 + String leftDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid+"/left"; + ImageUtils.createDir(leftDir); + //right文件夹 + String rightDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid+"/right"; + ImageUtils.createDir(rightDir); + //zip文件 +// File zipFile = new File(globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+".zip"); + String zipFile = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+".zip"; + //rgb文件 + String rgbFile = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/" + uuid+"/rgb.jpg"; + +// File left_ir0_file = new File(tempDir+"/left_ir0.jpg"); +// File left_ir1_file = new File(tempDir+"/left_ir1.jpg"); +// File left_ir2_file = new File(tempDir+"/left_ir2.jpg"); +// File right_ir0_file = new File(tempDir+"/right_ir0.jpg"); +// File right_ir1_file = new File(tempDir+"/right_ir1.jpg"); +// File right_ir2_file = new File(tempDir+"/right_ir2.jpg"); + + //保存rgb + String tempOrgImageFile = tenPerson.getOrgImageTemp(); + if (tempOrgImageFile != null && !tempOrgImageFile.isEmpty()) { + try { + // 调用statObject()来判断对象是否存在。 + // 如果不存在, statObject()抛出异常, + // 否则则代表对象存在。 + minioClient.statObject(minioConfig.getBucketName(), tempOrgImageFile); + + //判断人脸照片是否合格 + //1.保存到本地 + InputStream tempInputStream = minioClient.getObject(minioConfig.getBucketName(), tempOrgImageFile); +// String tempPath = globalValue.getStaticLocations() + "/";//+globalValue.getTempDir()+"/"; +// String tempOrgFilePath = tempPath + tempOrgImageFile; + int index; + byte[] bytes = new byte[1024]; + File outFile = new File(rgbFile); + FileOutputStream downloadFile = new FileOutputStream(outFile); + while ((index = tempInputStream.read(bytes)) != -1) { + downloadFile.write(bytes, 0, index); + downloadFile.flush(); + } + downloadFile.close(); + tempInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + try{ + ImageUtils.saveMultiFile(left_ir0, leftDir+"/ir0.jpg"); + ImageUtils.saveMultiFile(left_ir1, leftDir+"/ir1.jpg"); + ImageUtils.saveMultiFile(left_ir2, leftDir+"/ir2.jpg"); + ImageUtils.saveMultiFile(right_ir0, rightDir+"/ir0.jpg"); + ImageUtils.saveMultiFile(right_ir1, rightDir+"/ir1.jpg"); + ImageUtils.saveMultiFile(right_ir2, rightDir+"/ir2.jpg"); + }catch (Exception e){ + e.printStackTrace(); + } + + // 要压缩的文件或文件夹 + String sourceFile = tempDir; + // 压缩后的ZIP文件名 + String zipFileName = zipFile; + // 创建一个输出流将数据写入ZIP文件 + try { + FileOutputStream fos = new FileOutputStream(zipFileName); + ZipOutputStream zos = new ZipOutputStream(fos); + // 调用递归方法压缩文件或文件夹 + ZipExample.addToZipFile(sourceFile, sourceFile, zos); + System.out.println("文件已成功打包成 " + zipFileName); + zos.close(); + fos.close(); + }catch (Exception e){ + e.printStackTrace(); + } + + //保存minio' + try { +// String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //后缀名 + String userFileUrl = globalValue.getImagesDir() + "/" + + tenPerson.getCellId().toString() + "/" + + tenPerson.getPersonId().toString() + "/"; + String fileName = userFileUrl + "p_" + uuid + ".zip"; + InputStream inputStream = new FileInputStream(zipFile); + PutObjectOptions putObjectOptions = new PutObjectOptions(inputStream.available(), -1); + putObjectOptions.setContentType("application/zip"); + minioClient.putObject( + minioConfig.getBucketName(), fileName, inputStream, putObjectOptions); + inputStream.close(); + //删除文件: + File delZip = new File(zipFile); + delZip.delete(); + //删除临时文件夹 + ImageUtils.deleteFolder(new File(tempDir)); + //删除临时rgb文件 + File rgbFileTemp = new File(rgbFile); + rgbFileTemp.delete(); + + tenPerson.setSourceFile(fileName); + } catch (Exception e) { + } + } + + //----------------------------------掌静脉特征压缩包封装-------------------------------------- + + + int res = tenPersonService.save(tenPerson); + if (res==2) { + return R.error("照片未检测到人脸"); + } + return R.ok(); + } + + + @PostMapping("/palmCompare") + @RequiresPermissions("ten:person") + @ApiOperation(value = "保存人员信息") + public R palmCompare(@RequestPart(value = "ir0",required = false) MultipartFile left_ir0, + @RequestPart(value = "ir1",required = false) MultipartFile left_ir1) + { + String uuid = UUIDUtil.uuid(); + //文件夹 + String tempDir = globalValue.getStaticLocations()+"/"+globalValue.getTempDir()+"/"+uuid; + ImageUtils.createDir(tempDir); + + if (left_ir0!=null && !left_ir0.isEmpty() + && left_ir1!=null && !left_ir1.isEmpty()){ + + }else{ + //删除临时文件夹 + ImageUtils.deleteFolder(new File(tempDir)); + return R.error("比对照片不能为空"); + } + + try{ + String regFile = tempDir+"/ir0.jpg"; + String targetFile = tempDir+"/ir1.jpg"; + //保存文件 + ImageUtils.saveMultiFile(left_ir0, regFile); + ImageUtils.saveMultiFile(left_ir1, targetFile); + //提取特征 + + OutArg feature = new OutArg<>(); +// feature = FaceVerifyManager.the().getFeaturePicpalm_ir("/storage/emulated/0/30007/"+"right/ir"+i+".jpg"); + + //比对 + String resCode = PalmSDK.compareTwoImage(regFile, targetFile); + + //删除临时文件夹 + ImageUtils.deleteFolder(new File(tempDir)); + return R.ok().put("data",resCode); + }catch (Exception e){ + e.printStackTrace(); + } + return R.error(); + } } diff --git a/shapelight-admin/src/main/resources/application-dev.yml b/shapelight-admin/src/main/resources/application-dev.yml index 7298d25..3120f31 100644 --- a/shapelight-admin/src/main/resources/application-dev.yml +++ b/shapelight-admin/src/main/resources/application-dev.yml @@ -3,7 +3,7 @@ spring: type: com.alibaba.druid.pool.DruidDataSource druid: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.10.20:3306/cell_db_v9_check?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&rewriteBatchedStatements=true + url: jdbc:mysql://192.168.10.20:3306/cell_db_v10_pv_jd?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&rewriteBatchedStatements=true username: user password: user@server001 # url: jdbc:mysql://39.96.9.232:3306/cell_db_v8_http?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&rewriteBatchedStatements=true diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/natives/Palmlibrary.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/natives/Palmlibrary.java new file mode 100644 index 0000000..a3ca64a --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/natives/Palmlibrary.java @@ -0,0 +1,62 @@ +package net.shapelight.commons.engine.natives; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; +import net.shapelight.commons.engine.sdk.palm.FaceFeatureBase; +import net.shapelight.commons.engine.sdk.palm.OutArg; + +/** + * + */ + +public interface Palmlibrary extends Library { + + Palmlibrary INSTANTCE = (Palmlibrary) Native.load("palm", Palmlibrary.class); + + int InitModel(String jsonFile); + int ReleaseHandle(); + +// XT_API int PushRGBAndRegister(int width, int height, char *data, float **feature, char *matPath, int isPath); +// XT_API int PushRGBAndRecognize(int width, int height, char *data, float **feature, char *matPath, int isPath); +// +// XT_API int PushIrAndRegister(int width, int height, char *data, float **feature, char *matPath, int isPath); +// XT_API int PushIrAndRecognize(int width, int height, char *data, float **feature, char *matPath, int isPath); + + + int PushIrAndRegister(int width, int height, byte []data, PointerByReference feature); + + int PushRGBAndRegister(int width, int height, byte []data, PointerByReference feature); + + int PushIrAndRecognize(int width, int height, byte []data, PointerByReference feature); + + int PushRGBAndRecognize(int width, int height, byte []data, PointerByReference feature); + + + //XT_API int PalmSearchFaceFromList(int search_range, const float *query_feature, + // const float *gallery_features, int gallery_features_count, + // const int *feature_split, int feature_split_length, + // float **scores, int *scores_length, + // int **indices, int *indices_length); + + /** + * @brief 从人脸库搜索相似度最高的人脸,输出最相似人脸的置信度和人脸索引 + * @param[in] search_range 多特征时使用,一般传5 + * @param[in] query_feature 需要搜索的特征 + * @param[in] gallery_features 底库特征,人脸特征拼接成一维数组,方便jna调用 + * @param[in] gallery_features_count 底库特征个数,***注意:不是gallery_features的长度*** + * @param[in] feature_split 每段特征长度,元素个数与特征段数相等 + * @param[in] feature_split_length feature_split长度 + * @param[out] scores 输出置信度 + * @param[out] scores_length scores长度 + * @param[out] indices 输出人脸索引 + * @param[out] indices_length indices长度 + * @return 错误码,0表示成功,其他值表示失败 + */ + int PalmSearchFaceFromList(int search_range, float[] query_feature, + float[] gallery_features, int gallery_features_length, + int[] feature_split, int feature_split_length, + PointerByReference scores, IntByReference scores_length, + PointerByReference indices, IntByReference indices_length); +} diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/PalmSDK.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/PalmSDK.java new file mode 100644 index 0000000..ef2c6ab --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/PalmSDK.java @@ -0,0 +1,225 @@ +package net.shapelight.commons.engine.sdk; + +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; +import lombok.extern.slf4j.Slf4j; +import net.shapelight.commons.engine.natives.Clibrary; +import net.shapelight.commons.engine.natives.Palmlibrary; +import net.shapelight.commons.engine.sdk.palm.FaceFeatureBase; +import net.shapelight.commons.engine.sdk.palm.FaceFeatureFloat; +import net.shapelight.commons.engine.sdk.palm.OutArg; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + +//@Component +@Slf4j +public class PalmSDK { + + private static final int F_LENGHT = 512; + + private static final Palmlibrary instance = Palmlibrary.INSTANTCE; + + + public static int init() { + int code = instance.InitModel("palm/xt_palm_conf.json"); + return code; + } + + public static int release() { + int code = instance.ReleaseHandle(); + return code; + } + + + /** + * 掌静脉注册 + * @param width 宽 + * @param height 高 + * @param data 红外相机数据 ir数据 + * @param feature 特征 + * @return + */ + public static int PushIrAndRegister(int width, int height, byte[] data, OutArg feature) { + PointerByReference feature_ = new PointerByReference(); + + FaceFeatureFloat featureFloat = new FaceFeatureFloat(); + feature.value = featureFloat; + + log.debug("掌静脉PushIrAndRegister start"); + int ecode = instance.PushIrAndRegister(width,height,data,feature_); + log.debug("掌静脉PushIrAndRegister ecode=="+ecode); + + if (0 == ecode) { + if (feature_==null || feature_.getValue()==null){ + log.error("掌静脉PushIrAndRegister 返回特征为空"); + return -1; + } + featureFloat.feature = feature_.getValue().getFloatArray(0, F_LENGHT); + float center_x = feature_.getValue().getFloat(F_LENGHT*4); + float center_y = feature_.getValue().getFloat((F_LENGHT+1)*4); + log.error("掌静脉PushIrAndRegister center_x="+center_x+"center_y="+center_y); + } + + if (ecode==-1){ + log.debug("Xtface PushIrAndRegister faile"); + return -1; + } + return ecode; + } + + /** + * 掌静脉识别 + * @param width 宽 + * @param height 高 + * @param data 红外相机数据 + * @param feature 特征 + * @return + */ + public static int PushIrAndRecognize(int width, int height, byte[] data, OutArg feature) { + PointerByReference feature_ = new PointerByReference(); + FaceFeatureFloat featureFloat = new FaceFeatureFloat(); + feature.value = featureFloat; + log.debug("掌静脉PushIrAndRecognize start"); + int ecode = instance.PushIrAndRecognize(width,height,data,feature_); + log.debug("掌静脉PushIrAndRecognize ecode=="+ecode); + if (0 == ecode) { + if (feature_==null || feature_.getValue()==null){ + log.debug("掌静脉PushIrAndRecognize 返回特征为空"); + return -1; + } + featureFloat.feature = feature_.getValue().getFloatArray(0, F_LENGHT); + float center_x = feature_.getValue().getFloat(F_LENGHT*4); + float center_y = feature_.getValue().getFloat((F_LENGHT+1)*4); + log.debug("掌静脉PushIrAndRecognize center_x="+center_x+"center_y="+center_y); + } + if (ecode==-1){ + log.debug("Xtface PushIrAndRecognize faile"); + return -1; + } + return ecode; + } + + + /** + * 掌静脉注册 + * @param width 宽 + * @param height 高 + * @param data 红外相机数据 rgb数据 + * @param feature 特征 + * @return + */ + public static int PushRGBAndRegister(int width, int height, byte[] data, OutArg feature) { + PointerByReference feature_ = new PointerByReference(); + + FaceFeatureFloat featureFloat = new FaceFeatureFloat(); + feature.value = featureFloat; + + log.debug("掌静脉PushRGBAndRegister start"); + int ecode = instance.PushRGBAndRegister(width,height,data,feature_); + log.debug("掌静脉PushRGBAndRegister ecode=="+ecode); + + if (0 == ecode) { + if (feature_==null || feature_.getValue()==null){ + log.error("掌静脉PushRGBAndRegister 返回特征为空"); + return -1; + } + featureFloat.feature = feature_.getValue().getFloatArray(0, F_LENGHT); + float center_x = feature_.getValue().getFloat(F_LENGHT*4); + float center_y = feature_.getValue().getFloat((F_LENGHT+1)*4); + log.error("掌静脉PushIrAndRecognize center_x="+center_x+"center_y="+center_y); + } + + if (ecode==-1){ + log.debug("Xtface PushRGBAndRegister faile"); + return -1; + } + return ecode; + } + + public static int searchFromList_palm(int search_range, float[] query_feature, + List gallery_features, int[] feature_split, + OutArg scores, OutArg indices) { + float[] gallery_features_ = null; + int length = 0; + for (int i = 0; i < gallery_features.size(); i++) { + if (gallery_features.get(i) != null && gallery_features.get(i).length > 0) { + length = gallery_features.get(i).length; + gallery_features_ = new float[gallery_features.get(i).length * gallery_features.size()]; + break; + } + } + int ecode = -1; + if (gallery_features_ != null) { + for (int i = 0; i < gallery_features.size(); ++i) { + float[] fea = null; + if (gallery_features.get(i) != null) { + fea = gallery_features.get(i); + } else { + fea = new float[length]; + } + System.arraycopy(fea, 0, gallery_features_, i * fea.length, fea.length); + + } + PointerByReference scores_ = new PointerByReference(); + IntByReference scores_length_ = new IntByReference(); + PointerByReference indices_ = new PointerByReference(); + IntByReference indices_length_ = new IntByReference(); + ecode = instance.PalmSearchFaceFromList(search_range, query_feature, + gallery_features_, gallery_features.size(), + feature_split, feature_split.length, + scores_, scores_length_, + indices_, indices_length_); + if (0 == ecode) { + scores.value = scores_.getValue().getFloatArray(0, scores_length_.getValue()); + indices.value = indices_.getValue().getIntArray(0, indices_length_.getValue()); + for (int index:indices.value + ) { + log.debug("下标indices.value:"+index); + } + } + } + return ecode; + } + + + + public static String compareTwoImage(String regFile, String targetFile){ + + byte[] imageDataR1 = SdkImageUtils.image2byte(regFile); + byte[] imageDataR2 = SdkImageUtils.image2byte(targetFile); + int ecode = 0; + String res = "错误"; + try { + BufferedImage bufferedImageR1 = ImageIO.read(new ByteArrayInputStream(imageDataR1)); + byte[] nv21R1 = SdkImageUtils.getNV21(bufferedImageR1); + OutArg featureR1 = new OutArg<>(); + int regResR1 = PalmSDK.PushIrAndRegister(bufferedImageR1.getWidth(), bufferedImageR1.getHeight(), nv21R1, featureR1); + + BufferedImage bufferedImageR2 = ImageIO.read(new ByteArrayInputStream(imageDataR2)); + byte[] nv21R2 = SdkImageUtils.getNV21(bufferedImageR2); + OutArg featureR2 = new OutArg<>(); + int regResR2 = PalmSDK.PushIrAndRecognize(bufferedImageR2.getWidth(), bufferedImageR2.getHeight(), nv21R2, featureR2); + + float[] reg_feature = featureR1.value.getFeature_f(); + float[] target_feature = featureR2.value.getFeature_f(); + + int[] featureSplitpalm = {F_LENGHT}; + OutArg score = new OutArg<>(); + OutArg indices = new OutArg<>(); + List list_feature = new ArrayList<>(); + list_feature.add(reg_feature); + ecode = PalmSDK.searchFromList_palm(5, target_feature, list_feature, featureSplitpalm, score, indices); + + res = score.value[0]+""; + System.out.println("识别结果:"+ecode+" 识别分数:"+ res); + + }catch (Exception e){ + e.printStackTrace(); + } + return res; + } +} diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/SdkImageUtils.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/SdkImageUtils.java new file mode 100644 index 0000000..ddbee5d --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/SdkImageUtils.java @@ -0,0 +1,151 @@ +package net.shapelight.commons.engine.sdk; + +import javax.imageio.ImageIO; +import javax.imageio.stream.FileImageInputStream; +import java.awt.image.BufferedImage; +import java.io.*; + + +/** + * Created by ff135 on 2017/4/27. + *

+ * RGB转YUV: + *

+ * Y = 0.299 R + 0.587 G + 0.114 B + *

+ * U = - 0.1687 R - 0.3313 G + 0.5 B + 128 + *

+ * V = 0.5 R - 0.4187 G - 0.0813 B + 128 + *

+ * YUV转RGB + *

+ * R = Y + 1.402 (V - 128) + *

+ * G = Y - 0.34414 (U - 128) - 0.71414 (V - 128) + *

+ * B = Y + 1.772 (U - 128) + */ + +public class SdkImageUtils { + + + //图片到byte数组 + public static byte[] image2byte(String path){ + byte[] data = null; + FileImageInputStream input = null; + try { + input = new FileImageInputStream(new File(path)); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int numBytesRead = 0; + while ((numBytesRead = input.read(buf)) != -1) { + output.write(buf, 0, numBytesRead); + } + data = output.toByteArray(); + output.close(); + input.close(); + } + catch (FileNotFoundException ex1) { + ex1.printStackTrace(); + } + catch (IOException ex1) { + ex1.printStackTrace(); + } + return data; + } + + public static byte[] getNV21(BufferedImage bufferedImage) { +// BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData)); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + int[] pixels = bufferedImage.getRGB(0, 0, width, height, null, 0, width); + byte[] yuvs = encodeYUV420SP(pixels, width, height); + return yuvs; + } + + /** + * nv21  先u后v + * + * @return + * @paramargb + * @paramwidth + * @paramheight + */ + + public static byte[] encodeYUV420SP(int[] argb, int width, int height) { + int size = (int) ((Math.ceil(width / 2.0)) * (Math.ceil(height / 2.0))); + int frameSize = width * height; + byte[] yuvs = new byte[frameSize + size * 2]; + int y = 0, u = 0, v = 0; + int r = 0, g = 0, b = 0, a = 0; + int index = 0, uvindex = frameSize; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + a = (argb[index] & 0xff000000) >> 24;// a is not used obviously + r = (argb[index] & 0xff0000) >> 16; + g = (argb[index] & 0xff00) >> 8; + b = (argb[index] & 0xff) >> 0; +//转换公式 + y = (int) (0.299 * r + 0.587 * g + 0.114 * b); + u = (int) (-0.1687 * r - 0.3313 * g + 0.5 * b + 128); + v = (int) (0.5 * r - 0.4187 * g - 0.0813 * b + 128); +// System.out.println("x:" + i + "y:" + j + "  y:" + y + " u:" + u + " v:" + v); + yuvs[index++] = (byte) ((y < 0) ? 0 : ((y > 255) ? 255 : y)); + if (i % 2 == 0 && j % 2 == 0) { + yuvs[uvindex++] = (byte) ((u < 0) ? 0 : ((u > 255) ? 255 : u)); + yuvs[uvindex++] = (byte) ((v < 0) ? 0 : ((v > 255) ? 255 : v)); +//                    yuvs[uvindex++]=(byte)120; +//                    yuvs[uvindex++] = (byte) ((v < 0) ? 0 : ((v > 255) ? 255 : v)); +//                    yuvs[uvindex++]=(byte)240; + } + } + } + return yuvs; + } + + public static int[] decodeYUV420sp(byte[] yuvs, int width, int height) { + int frameSize = width * height; + int[] rgbs = new int[frameSize]; + int index = 0; + int uvindex = frameSize; + int u = 0, v = 0, y = 0; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (i % 2 == 0 && j % 2 == 0) { + u = yuvs[uvindex++]; + v = yuvs[uvindex++]; + } +//保存到数组中去 + y = yuvs[index]; + rgbs[index++] = yuv2Rgb(y, u, v); + } + } + return rgbs; + } + + public static int yuv2Rgb(int y, int u, int v) { +// 转换公式 + int r = (int) ((y & 0xff) + 1.402 * ((v & 0xff) - 128)); + int g = (int) ((y & 0xff) - 0.34414 * ((u & 0xff) - 128) - 0.71414 * ((v & 0xff) - 128)); + int b = (int) ((y & 0xff) + 1.772 * ((u & 0xff) - 128)); + r = (r < 0 ? 0 : r > 255 ? 255 : r); + g = (g < 0 ? 0 : g > 255 ? 255 : g); + b = (b < 0 ? 0 : b > 255 ? 255 : b); + return (0xff << 24) + (r << 16) + (g << 8) + b; + } + + + public static void main(String[] args) { + +// File imgFile = new File("/home/huangyifang/gb/palm/noface.jpg"); + String path = "/home/huangyifang/gb/palm/noface.jpg"; + byte[] imageData = image2byte(path); + try { + BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData)); + byte[] nv21 = getNV21(bufferedImage); + System.out.println("000000000000000000"); + }catch (Exception e){ + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/main.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/main.java index 5f46fed..3fdc841 100644 --- a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/main.java +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/main.java @@ -1,6 +1,49 @@ package net.shapelight.commons.engine.sdk; +import net.shapelight.commons.engine.sdk.palm.FaceFeatureBase; +import net.shapelight.commons.engine.sdk.palm.OutArg; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + public class main { + public static void testCompare(){ + String r1 = "/home/huangyifang/gb/palm/ir0.jpg"; + String r2 = "/home/huangyifang/gb/palm/ir1.jpg"; + + + byte[] imageDataR1 = SdkImageUtils.image2byte(r1); + byte[] imageDataR2 = SdkImageUtils.image2byte(r2); + int ecode = 0; + try { + BufferedImage bufferedImageR1 = ImageIO.read(new ByteArrayInputStream(imageDataR1)); + byte[] nv21R1 = SdkImageUtils.getNV21(bufferedImageR1); + OutArg featureR1 = new OutArg<>(); + int regResR1 = PalmSDK.PushIrAndRegister(bufferedImageR1.getWidth(), bufferedImageR1.getHeight(), nv21R1, featureR1); + + BufferedImage bufferedImageR2 = ImageIO.read(new ByteArrayInputStream(imageDataR2)); + byte[] nv21R2 = SdkImageUtils.getNV21(bufferedImageR2); + OutArg featureR2 = new OutArg<>(); + int regResR2 = PalmSDK.PushIrAndRecognize(bufferedImageR2.getWidth(), bufferedImageR2.getHeight(), nv21R2, featureR2); + + float[] target_feature = featureR2.value.getFeature_f(); + float[] reg_feature = featureR1.value.getFeature_f(); + + int[] featureSplitpalm = {128}; + OutArg score = new OutArg<>(); + OutArg indices = new OutArg<>(); + List list_feature = new ArrayList<>(); + list_feature.add(reg_feature); + ecode = PalmSDK.searchFromList_palm(5, target_feature, list_feature, featureSplitpalm, score, indices); + System.out.println("识别结果:"+ecode); + + }catch (Exception e){ + + } + } public static void main(String[] args){ /*Clibrary instance = Clibrary.INSTANTCE; @@ -13,9 +56,34 @@ public class main { String orgImgPath = "D:/1.jpg"; String faceImgPath = "D:/2.jpg"; - int i = PicSDK.getFace(orgImgPath,faceImgPath); - //PicSDK.extract("/home/shapelight/0_image.jpg"); - System.out.println(i); +// int i = PicSDK.getFace(orgImgPath,faceImgPath); +// PicSDK.extract("/home/shapelight/0_image.jpg"); +// System.out.println(i); + +// PalmSDK.InitModel("/home/huangyifang/gb/palm/xt_palm_conf.json"); + int res = PalmSDK.init(); + System.out.println("初始化掌静脉sdk:"+res); + String rgbPath = "/home/huangyifang/gb/palm/test/p_376b2546e00740269fd51cfc8c477e95/left/ir0.jpg"; + String irPath = "/home/huangyifang/gb/palm/test/p_376b2546e00740269fd51cfc8c477e95/left/ir1.jpg"; + byte[] imageData = SdkImageUtils.image2byte(irPath); + try { + BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData)); + byte[] nv21 = SdkImageUtils.getNV21(bufferedImage); + + + OutArg feature = new OutArg<>(); + int regRes = PalmSDK.PushIrAndRegister(bufferedImage.getWidth(),bufferedImage.getHeight(),nv21,feature); + System.out.println("注册结果:"+regRes); + }catch (Exception e){ + e.printStackTrace(); + } + +// testCompare(); + + String r1 = "/home/huangyifang/gb/palm/test/p_376b2546e00740269fd51cfc8c477e95/left/ir0.jpg"; + String r2 = "/home/huangyifang/gb/palm/test/p_376b2546e00740269fd51cfc8c477e95/right/ir2.jpg"; + + PalmSDK.compareTwoImage(r1,r2); } diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureBase.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureBase.java new file mode 100644 index 0000000..083a3c4 --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureBase.java @@ -0,0 +1,9 @@ +package net.shapelight.commons.engine.sdk.palm; + +public interface FaceFeatureBase { + byte[] getFeature(); + + int[] getFeatureSplit(); + + float[] getFeature_f(); +} diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureFloat.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureFloat.java new file mode 100644 index 0000000..d8fde33 --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/FaceFeatureFloat.java @@ -0,0 +1,36 @@ +package net.shapelight.commons.engine.sdk.palm; + + +import net.shapelight.commons.engine.sdk.palm.FaceFeatureBase; + +public class FaceFeatureFloat implements FaceFeatureBase { + public float[] feature; + public int[] featureSplit; + + public FaceFeatureFloat(){} + + public FaceFeatureFloat(float[] feature, int[] featureSplit){ + this.feature = feature; + this.featureSplit = featureSplit; + } + + @Override + public byte[] getFeature() { + + return null; + } + + @Override + public int[] getFeatureSplit() { + int[] byteSplit = new int[featureSplit.length]; + for(int i = 0; i < byteSplit.length; ++i){ + byteSplit[i] = featureSplit[i] * 4; + } + return byteSplit; + } + + @Override + public float[] getFeature_f() { + return feature; + } +} diff --git a/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/OutArg.java b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/OutArg.java new file mode 100644 index 0000000..5479031 --- /dev/null +++ b/shapelight-engine/src/main/java/net/shapelight/commons/engine/sdk/palm/OutArg.java @@ -0,0 +1,12 @@ +package net.shapelight.commons.engine.sdk.palm; + +public class OutArg { + public T value; + + public OutArg() { + } + + private void setValue(Object obj) { + value = (T) obj; + } +} \ No newline at end of file