Commit 452a0ecd authored by 宋柯's avatar 宋柯

双眼皮

parent e4336789
1.JPG

95.4 KB

......@@ -3,24 +3,6 @@ project(BeautyCamera)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#find_package(nlohmann_json 3.2.0 REQUIRED)
#target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
#Poco
#find_package(Poco CONFIG REQUIRED Util Data Net XML Zip)
#message(STATUS "Using Poco ${Poco_VERSION}")
# <------------ add hiredis dependency --------------->
#find_path(HIREDIS_HEADER hiredis)
#message(STATUS "Using HIREDIS_HEADER ${HIREDIS_HEADER}")
#find_library(HIREDIS_LIB hiredis)
# <------------ add redis-plus-plus dependency -------------->
# NOTE: this should be *sw* NOT *redis++*
#find_path(REDIS_PLUS_PLUS_HEADER sw)
#find_library(REDIS_PLUS_PLUS_LIB redis++)
#opencv
find_package(OpenCV)
......@@ -29,10 +11,6 @@ find_package(Poco CONFIG REQUIRED JSON Foundation Crypto NetSSL Util Data Net XM
#dlib
find_package(dlib REQUIRED)
include_directories(${dlib_INCLUDE_DIRS})
#FIND_PACKAGE(OpenMP REQUIRED)
#if(OPENMP_FOUND)
# set(CMAKE_C_FLAGS "${OpenMP_C_FLAGS}")
#endif()
#openssl
find_package(OpenSSL REQUIRED)
......@@ -41,17 +19,5 @@ include_directories(/usr/local/Cellar/openssl@1.1/1.1.1i/include/)
aux_source_directory(. SRCS)
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
#add_executable(main f_BeautyCamera.cpp ${SRCS})
#target_link_libraries(main ${OpenCV_LIBS} ${Poco_LIBRARIES})
#add_executable(gender gender.cpp ${SRCS})
#target_link_libraries(gender ${OpenCV_LIBS} ${Poco_LIBRARIES})
add_executable(beautyIris f_BeautyIris.cpp ${SRCS})
target_link_libraries(beautyIris ${OpenCV_LIBS} ${Poco_LIBRARIES} PocoFoundation PocoNet PocoUtil ${dlib_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY})
#target_link_libraries(beautyIris ${OpenCV_LIBS} ${Poco_LIBRARIES} libdlib.a X11 pthread)
#target_link_libraries(helloworld
# ${Poco_LIBRARIES}
# ${HIREDIS_LIB}
# ${REDIS_PLUS_PLUS_LIB}
# nlohmann_json::nlohmann_json
# rdkafka++)
\ No newline at end of file
add_executable(lid f_EyeLid.cpp ${SRCS})
target_link_libraries(lid ${OpenCV_LIBS} ${Poco_LIBRARIES} PocoFoundation PocoNet PocoUtil ${dlib_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY})
#include"TRGB2HSV.h"
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
void RGB2HSV(unsigned char R, unsigned char G, unsigned char B, float* h, float* s, float * v)
{
float min, max;
float r = R / 255.0;
float g = G / 255.0;
float b = B / 255.0;
min = MIN2(r,MIN2(g,b));
max = MAX2(r,MAX2(g,b));
if (max == min)
*h = 0;
else if (max == r && g >= b)
*h = 60.0 * (g - b) / (max - min);
else if (max == r && g < b)
*h = 60.0 * (g - b) / (max - min) + 360.0;
else if (max == g)
*h = 60.0 * (b - r) / (max - min) + 120.0;
else if (max == b)
*h = 60.0 * (r - g) / (max - min) + 240.0;
*h = CLIP3(*h, 0, 360);
if (max == 0)
*s = 0;
else
*s = (max - min) / max;
*v = max;
};
void HSV2RGB(float h, float s, float v, unsigned char* R, unsigned char *G, unsigned char *B)
{
float q = 0, p = 0, t = 0, f = 0, r = 0, g = 0, b = 0;
int hN = 0;
if(h == 360)
h = 0;
if (h < 0)
h = 360 + h;
hN = (int)((int)h / 60);
f = h / 60.0f - hN;
p = v * (1.0 - s);
q = v * (1.0 - f * s);
t = v * (1.0 - (1.0 - f) * s);
switch (hN)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
default:
break;
}
*R = (unsigned char)CLIP3((r * 255.0),0,255);
*G = (unsigned char)CLIP3((g * 255.0),0,255);
*B = (unsigned char)CLIP3((b * 255.0),0,255);
};
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: RGB2HSV
*************************************************************************/
#ifndef __RGB2HSI__
#define __RGB2HSI__
void RGB2HSV(unsigned char R, unsigned char G, unsigned char B, float *H, float *S, float *V);
void HSV2RGB(float H, float S, float V, unsigned char * R, unsigned char * G, unsigned char *B);
#endif
\ No newline at end of file
#include"TRGB2YCbCr.h"
#include <stdlib.h>
#include <stdio.h>
#include "math.h"
#include <string.h>
const float YCbCrYRF = 0.299F; // RGB转YCbCr的系数(浮点类型)
const float YCbCrYGF = 0.587F;
const float YCbCrYBF = 0.114F;
const float YCbCrCbRF = -0.168736F;
const float YCbCrCbGF = -0.331264F;
const float YCbCrCbBF = 0.500000F;
const float YCbCrCrRF = 0.500000F;
const float YCbCrCrGF = -0.418688F;
const float YCbCrCrBF = -0.081312F;
const float RGBRYF = 1.00000F; // YCbCr转RGB的系数(浮点类型)
const float RGBRCbF = 0.0000F;
const float RGBRCrF = 1.40200F;
const float RGBGYF = 1.00000F;
const float RGBGCbF = -0.34414F;
const float RGBGCrF = -0.71414F;
const float RGBBYF = 1.00000F;
const float RGBBCbF = 1.77200F;
const float RGBBCrF = 0.00000F;
const int Shift = 20;
const int HalfShiftValue = 1 << (Shift - 1);
const int YCbCrYRI = (int)(YCbCrYRF * (1 << Shift) + 0.5); // RGB转YCbCr的系数(整数类型)
const int YCbCrYGI = (int)(YCbCrYGF * (1 << Shift) + 0.5);
const int YCbCrYBI = (int)(YCbCrYBF * (1 << Shift) + 0.5);
const int YCbCrCbRI = (int)(YCbCrCbRF * (1 << Shift) + 0.5);
const int YCbCrCbGI = (int)(YCbCrCbGF * (1 << Shift) + 0.5);
const int YCbCrCbBI = (int)(YCbCrCbBF * (1 << Shift) + 0.5);
const int YCbCrCrRI = (int)(YCbCrCrRF * (1 << Shift) + 0.5);
const int YCbCrCrGI = (int)(YCbCrCrGF * (1 << Shift) + 0.5);
const int YCbCrCrBI = (int)(YCbCrCrBF * (1 << Shift) + 0.5);
const int RGBRYI = (int)(RGBRYF * (1 << Shift) + 0.5); // YCbCr转RGB的系数(整数类型)
const int RGBRCbI = (int)(RGBRCbF * (1 << Shift) + 0.5);
const int RGBRCrI = (int)(RGBRCrF * (1 << Shift) + 0.5);
const int RGBGYI = (int)(RGBGYF * (1 << Shift) + 0.5);
const int RGBGCbI = (int)(RGBGCbF * (1 << Shift) + 0.5);
const int RGBGCrI = (int)(RGBGCrF * (1 << Shift) + 0.5);
const int RGBBYI = (int)(RGBBYF * (1 << Shift) + 0.5);
const int RGBBCbI = (int)(RGBBCbF * (1 << Shift) + 0.5);
const int RGBBCrI = (int)(RGBBCrF * (1 << Shift) + 0.5);
void RGBToYCbCr(int R, int G, int B, int*Y,int*Cb, int* Cr)
{
*Y = ((YCbCrYRI * R + YCbCrYGI * G + YCbCrYBI * B + HalfShiftValue) >> Shift);
*Cb = (128 + ((YCbCrCbRI * R + YCbCrCbGI * G + YCbCrCbBI * B + HalfShiftValue) >> Shift));
*Cr = (128 + ((YCbCrCrRI * R + YCbCrCrGI * G + YCbCrCrBI * B + HalfShiftValue) >> Shift));
}
void YCbCrToRGB(int Y, int Cb, int Cr, int*R,int*G, int* B)
{
Cb = Cb - 128; Cr = Cr - 128;
*R = Y + ((RGBRCrI * Cr + HalfShiftValue) >> Shift);
*G = Y + ((RGBGCbI * Cb + RGBGCrI * Cr + HalfShiftValue) >> Shift);
*B = Y + ((RGBBCbI * Cb + HalfShiftValue) >> Shift);
if (*R > 255) *R = 255; else if (*R < 0) *R = 0;
if (*G > 255) *G = 255; else if (*G < 0) *G = 0;
if (*B > 255) *B = 255; else if (*B < 0) *B = 0;
}
\ No newline at end of file
/*************************************************
Copyright: Copyright HZ.
Author: Hu Yaowu
Date: 2015-04-21
Mail: dongtingyueh@163.com
Description:RGB to YCbCr.
**************************************************/
#ifndef TRGB2YCbCr
#define TRGB2YCbCr
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void RGBToYCbCr(int R, int G, int B, int*Y,int*Cb, int* Cr);
void YCbCrToRGB(int Y, int Cb, int Cr, int*R,int*G, int* B);
#endif
\ No newline at end of file
#include"TRGB2YUV.h"
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
void RGB2YUV(unsigned char R, unsigned char G, unsigned char B, int *Y, int* U, int*V)
{
......
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: RGB2YUV
*************************************************************************/
#ifndef __RGB2YUV__
#define __RGB2YUV__
......
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9F6555E5-E791-44C8-B90B-4FFB3AD7C52D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>TestDemo_C</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\TestDemo\bin\Debug</OutDir>
<EmbedManifest>false</EmbedManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\TestDemo\bin\Release</OutDir>
<EmbedManifest>false</EmbedManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TESTDEMO_C_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TESTDEMO_C_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Commen.h" />
<ClInclude Include="f_BeautyCamera.h" />
<ClInclude Include="f_Commen_MixLayer.h" />
<ClInclude Include="f_GaussFilter.h" />
<ClInclude Include="f_LaplaceSharpen.h" />
<ClInclude Include="f_LUTFilter.h" />
<ClInclude Include="f_SkinDetect.h" />
<ClInclude Include="f_SkinPDF.h" />
<ClInclude Include="f_SkinColor.h" />
<ClInclude Include="f_SmartBlur.h" />
<ClInclude Include="f_SoftSkin.h" />
<ClInclude Include="f_SoftSkin_ChannelMethod.h" />
<ClInclude Include="f_SoftSkin_DetailsAddingMethod.h" />
<ClInclude Include="f_SoftSkin_HPMethod.h" />
<ClInclude Include="f_SoftSkin_MixMethod.h" />
<ClInclude Include="f_SurfaceBlur.h" />
<ClInclude Include="TRGB2HSV.h" />
<ClInclude Include="TRGB2YCbCr.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="f_BeautyCamera.cpp" />
<ClCompile Include="f_Commen_MixLayer.cpp" />
<ClCompile Include="f_GaussFilter.cpp" />
<ClCompile Include="f_LaplaceSharpen.cpp" />
<ClCompile Include="f_LUTFilter.cpp" />
<ClCompile Include="f_SkinDetect.cpp" />
<ClCompile Include="f_SkinPDF.cpp" />
<ClCompile Include="f_SkinColor.cpp" />
<ClCompile Include="f_SmartBlur.cpp" />
<ClCompile Include="f_SoftSkin.cpp" />
<ClCompile Include="f_SoftSkin_ChannelMethod.cpp" />
<ClCompile Include="f_SoftSkin_DetailsAddingMethod.cpp" />
<ClCompile Include="f_SoftSkin_HPMethod.cpp" />
<ClCompile Include="f_SoftSkin_MixMethod.cpp" />
<ClCompile Include="f_SurfaceBlur.cpp" />
<ClCompile Include="TRGB2HSV.cpp" />
<ClCompile Include="TRGB2YCbCr.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="TRGB2YCbCr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SkinPDF.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Commen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_GaussFilter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SoftSkin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SmartBlur.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SkinDetect.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TRGB2HSV.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_LUTFilter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SkinColor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SoftSkin_ChannelMethod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SoftSkin_HPMethod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SurfaceBlur.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SoftSkin_MixMethod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_Commen_MixLayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_SoftSkin_DetailsAddingMethod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_LaplaceSharpen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="f_BeautyCamera.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="TRGB2YCbCr.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SkinPDF.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_GaussFilter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SoftSkin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SmartBlur.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SkinDetect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TRGB2HSV.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_LUTFilter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SkinColor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SoftSkin_ChannelMethod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SoftSkin_HPMethod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SurfaceBlur.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SoftSkin_MixMethod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_Commen_MixLayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_SoftSkin_DetailsAddingMethod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_LaplaceSharpen.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="f_BeautyCamera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
\ No newline at end of file
//
// Created by EDZ on 2021/4/16.
//
#include "ZBase64.h"
string ZBase64::Encode(const unsigned char* Data,int DataByte,string& strEncode)
{
//编码表
const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//返回值
unsigned char Tmp[4]={0};
int LineLength=0;
for(int i=0;i<(int)(DataByte / 3);i++)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
Tmp[3] = *Data++;
strEncode+= EncodeTable[Tmp[1] >> 2];
strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
strEncode+= EncodeTable[Tmp[3] & 0x3F];
if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;}
}
//对剩余数据进行编码
int Mod=DataByte % 3;
if(Mod==1)
{
Tmp[1] = *Data++;
strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];
strEncode+= "==";
}
else if(Mod==2)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];
strEncode+= "=";
}
return strEncode;
}
//
// Created by EDZ on 2021/4/16.
//
#ifndef HELLOWORLD_ZBASE64_H
#define HELLOWORLD_ZBASE64_H
#include <string>
using namespace std;
class ZBase64
{
public:
/*编码
DataByte
[in]输入的数据长度,以字节为单位
*/
string Encode(const unsigned char* Data,int DataByte,string& strEncode);
};
#endif //HELLOWORLD_ZBASE64_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include"f_SkinDetect.h"
#include"../TRGB2YCbCr.h"
#include"../TRGB2HSV.h"
#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define CLIP3(x, a, b) MIN2(MAX2(a,x), b)
/*************************************************************************
*Function: Skin detection in RGB color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: Human skin color clustering for face detection.
**************************************************************************/
int f_SkindetectionRGB(unsigned char* srcData, int width, int height, int stride)
{
int ret = 0;
unsigned char* pSrc = srcData;
int R, G, B;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
B = pSrc[0];
G = pSrc[1];
R = pSrc[2];
if(!((R > 95) && (G > 40) && (B > 20) && (R > G) && (R > B) && (MAX2(R, G, B)-MIN2(R, G, B) > 15) && (abs(R - G) > 15)))
{
pSrc[0] = 0;
pSrc[1] = 0;
pSrc[2] = 0;
}
pSrc += 4;
}
}
return ret;
}
/*************************************************************************
*Function: Skin detection in hsv color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: Skin color enhancement based on favorite skin color in HSV color space.
**************************************************************************/
int f_SkindetectionHSV(unsigned char* srcData, int width, int height, int stride)
{
int ret = 0;
unsigned char* pSrc = srcData;
int R, G, B;
float H, S, V;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
B = pSrc[0];
G = pSrc[1];
R = pSrc[2];
RGB2HSV(R, G, B, &H, &S, &V);
if (!(((S >= 0.1) && (S <= 0.68)) && ((V >= 0.13 && V <= 0.25 && H >= ((0.4 - V) / 0.014) && H <= ((V + 0.062) / 0.01)) || ((V > 0.25) && (V <= 0.38) && (H >= (0.4 - V) / 0.014) && (H <= (0.67 - V) / 0.014)) || ((V > 0.38) && (V <= 0.46) && (H >= (V - 0.34) / 0.03) && (H <= (0.67 - V) / 0.014)) ||
((V > 0.46) && (V <= 0.6) && (H >= (V - 0.34) / 0.03) && (H <= (V - 0.31) / 0.009)) || ((V > 0.6) && (V <= 0.76) && (H >= (0.91 - V) / 0.14) && (H <= (V - 0.31) / 0.009)) || ((V > 0.76) && (V <= 0.91) && (H >= (0.91 - V) / 0.14) && (H <= (1.17 - V) / 0.0082)) || ((V > 0.91) && (V <= 1) && (H >= (V - 0.91) / 0.0041) && (H <= (1.17 - V) / 0.0082)))))
{
pSrc[0] = 0;
pSrc[1] = 0;
pSrc[2] = 0;
}
pSrc += 4;
}
}
return ret;
}
/*************************************************************************
*Function: Skin detection in ycgcr color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: YCgCr��ɫ�ռ�ķ�ɫ����������ⷨ.
**************************************************************************/
int f_SkindetectionYCgCr(unsigned char* srcData, int width, int height, int stride)
{
int ret = 0;
unsigned char* pSrc = srcData;
int R, G, B;
float Cr, Cg, Cb;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
B = pSrc[0];
G = pSrc[1];
R = pSrc[2];
Cg = 128 - 0.318f * R + 0.4392f * G - 0.1212f * B;
Cr = 128 + 0.4392f * R - 0.3677f * G - 0.0714f * B;
if (!((Cg >= 85) && (Cg <= 135) && ((Cr <= (280 - Cg)) && (Cr >= (260 - Cg)))))
{
pSrc[0] = 0;
pSrc[1] = 0;
pSrc[2] = 0;
}
pSrc += 4;
}
}
return ret;
}
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-4-23
Mail: dongtingyueh@163.com
Description: Skin detection.
*************************************************************************/
#ifndef __T_BEEPS_FILTER__
#define __T_BEEPS_FILTER__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: Skin detection in RGB color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: Human skin color clustering for face detection.
**************************************************************************/
EXPORT int f_SkindetectionRGB(unsigned char* srcData, int width, int height, int stride);
/*************************************************************************
*Function: Skin detection in hsv color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: Skin color enhancement based on favorite skin color in HSV color space.
**************************************************************************/
EXPORT int f_SkindetectionHSV(unsigned char* srcData, int width, int height, int stride);
/*************************************************************************
*Function: Skin detection in ycgcr color space
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
*Refference: YCgCr颜色空间的肤色据类人脸检测法.
**************************************************************************/
EXPORT int f_SkindetectionYCgCr(unsigned char* srcData, int width, int height, int stride);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_SkindetectionRGB(unsigned char* srcData, int width, int height, int stride);
int f_SkindetectionHSV(unsigned char* srcData, int width, int height, int stride);
int f_SkindetectionYCgCr(unsigned char* srcData, int width, int height, int stride);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"../Commen.h"
#include"../f_GaussFilter.h"//1.5.2
#include"../f_SkinPDF.h" //3.10
//#include"disabled/f_SkinDetect.h"//3.9
#include"../f_SmartBlur.h"//3.6
#include"f_SoftSkin.h"
/*************************************************************************
*Function: SOFT SKIN
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_Softskin(unsigned char* srcData, int width, int height, int stride, int skinMode, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* smoothData = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(smoothData, srcData, sizeof(unsigned char) * length);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(skinPDF, srcData, sizeof(unsigned char) * length);
int smoothRadius = CLIP3(8 * width * height / (500 * 500), 3,12);
int smoothThreshold = 38;
int maskSmoothRadius = 3;
ret = f_SmartBlur(smoothData, width, height, stride, smoothRadius, smoothThreshold);
if(skinMode == 0)
{
ret = f_SkindetectionYCgCr(skinPDF, width, height, stride);
maskSmoothRadius = 6;
}
else
{
ret = f_SkinPDF(skinPDF, width, height, stride);
}
ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
unsigned char* pMask = skinPDF;
unsigned char* pSmooth = smoothData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int mask = (pMask[0] + pMask[1] + pMask[2]) / 3;
int b = (pSrc[0] * (255 - mask) + pSmooth[0] * mask) / 255;
int g = (pSrc[1] * (255 - mask) + pSmooth[1] * mask) / 255;
int r = (pSrc[2] * (255 - mask) + pSmooth[2] * mask) / 255;
pSrc[0] = CLIP3((b * ratio + pSrc[0] * (100 - ratio)) / 100, 0, 255);
pSrc[1] = CLIP3((g * ratio + pSrc[1] * (100 - ratio)) / 100, 0, 255);
pSrc[2] = CLIP3((r * ratio + pSrc[2] * (100 - ratio)) / 100, 0, 255);
pSrc += 4;
pSmooth += 4;
pMask += 4;
}
}
free(skinPDF);
free(smoothData);
return ret;
};
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Soft skin .
*************************************************************************/
#ifndef __T_SOFT_SKIN__
#define __T_SOFT_SKIN__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SOFT SKIN
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_Softskin(unsigned char* srcData, int width, int height, int stride, int skinMode, int ratio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_Softskin(unsigned char* srcData, int width, int height, int stride, int skinMode, int ratio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"Commen.h"
#include"f_AffineTransfrom.h"
/*************************************************************************
*Function: Affinetransfrom matrix compute
*Params:
*x: x of input points
*y: y of input points
*tx: x of output points
*ty: y of output points
*hMatrix: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*Return: NULL
**************************************************************************/
void f_AffinetransformMetrixCompute(float x1, float y1, float x2, float y2, float x3, float y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float hMatrix[6])
{
//求行列式|A|
float detA;
detA = tx1 * ty2 + tx2 * ty3 + tx3 * ty1 - tx3 * ty2 - tx1 * ty3 - tx2 * ty1;
// 求伴随矩阵A*
float A11, A12, A13, A21, A22, A23, A31, A32, A33;
A11 = ty2 - ty3;
A21 = -(ty1 - ty3);
A31 = ty1 - ty2;
A12 = -(tx2 - tx3);
A22 = tx1 - tx3;
A32 = -(tx1 - tx2);
A13 = tx2 * ty3 - tx3 * ty2;
A23 = -(tx1 * ty3 - tx3 * ty1);
A33 = tx1 * ty2 - tx2 * ty1;
//求变换矩阵H=A*/|A|
//float texMatrix[6]={0};
hMatrix[0] = (x1 * A11 + x2 * A21 + x3 * A31) / detA;
hMatrix[1] = (x1 * A12 + x2 * A22 + x3 * A32) / detA;
hMatrix[2] = (x1 * A13 + x2 * A23 + x3 * A33) / detA;
hMatrix[3] = (y1 * A11 + y2 * A21 + y3 * A31) / detA;
hMatrix[4] = (y1 * A12 + y2 * A22 + y3 * A32) / detA;
hMatrix[5] = (y1 * A13 + y2 * A23 + y3 * A33) / detA;
};
/*************************************************************************
*Function: getWHFromHMatrix
*Params:
*width: source image width
*height: source image height
*H: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*wh: the size of image outputs, wh[0]=dWidth, wh[1] = dHeight
*Return: NULL
**************************************************************************/
void getWHFromHMatrix(int width, int height, float H[6], int wh[2])
{
int x0 = (H[0] * 0 + H[1] * 0 + H[2] + 0.5);
int y0 = (H[3] * 0 + H[4] * 0 + H[5] + 0.5);
int x1 = (H[0] * (float)(width - 1) + H[1] * (float)(height - 1) + H[2] + 0.5);
int y1 = (H[3] * (float)(width - 1) + H[4] * (float)(height - 1) + H[5] + 0.5);
int x2 = (H[0] * (float)(width - 1) + H[1] * 0 + H[2] + 0.5);
int y2 = (H[3] * (float)(width - 1) + H[4] * 0 + H[5] + 0.5);
int x3 = (H[0] * 0 + H[1] * (float)(height - 1) + H[2] + 0.5);
int y3 = (H[3] * 0 + H[4] * (float)(height - 1) + H[5] + 0.5);
wh[0] = MAX2(x0, MAX2(x1, MAX2(x2, x3))) - MIN2(x0, MIN2(x1, MIN2(x2, x3)));
wh[1] = MAX2(y0, MAX2(y1, MAX2(y2, y3))) - MIN2(y0, MIN2(y1, MIN2(y2, y3)));
};
/*************************************************************************
*Function: Affinetransfrom
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*H: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*dstData: output image buffer with format bgra32
*dWidth: width of image outputs
*dHeight: height of image outputs
*dStride: Stride of image outputs
*Return: 0-OK,other failed
**************************************************************************/
int f_AffineTransform(unsigned char* srcData, int width, int height, int stride, float H[6], unsigned char* dstData, int dWidth, int dHeight, int dStride)
{
int ret = 0;
unsigned char* pSrc = dstData;
int tx, ty, pos;
int offset[2];
offset[0] = ((dWidth/2.0) - (H[0]*(width/2.0) + H[1]*(height/2.0) + H[2]) + 0.5);
offset[1] = ((dHeight/2.0) - (H[3]*(width/2.0) + H[4]*(height/2.0) + H[5]) + 0.5);
H[2] += offset[0];
H[5] += offset[1];
pSrc = srcData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
tx = CLIP3(((H[0] * (float)(i) + H[1] * (float)(j) + H[2])), 0, dWidth - 1);
ty = CLIP3(((H[3] * (float)(i) + H[4] * (float)(j) + H[5])), 0, dHeight - 1);
pos = (tx << 2) + ty * dStride;
dstData[pos] = pSrc[0];
dstData[pos + 1] = pSrc[1];
dstData[pos + 2] = pSrc[2];
dstData[pos + 3] = 255;
pSrc += 4;
}
}
return ret;
};
\ No newline at end of file
......@@ -4,10 +4,10 @@ Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Skin White.
Description: Affinetransfrom .
*************************************************************************/
#ifndef __T_SKIN_WHITE__
#define __T_SKIN_WHITE__
#ifndef __T_AFFINE_TRANSFROM__
#define __T_AFFINE_TRANSFROM__
#ifdef _MSC_VER
......@@ -19,52 +19,50 @@ Description: Skin White.
#endif
/*************************************************************************
*Function: SKIN WHITE
*Function: Affinetransfrom matrix compute
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*skinMask: skin mask
*lutData: 32BGRA buffer of lut image.
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
*x: x of input points
*y: y of input points
*tx: x of output points
*ty: y of output points
*hMatrix: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*Return: NULL
**************************************************************************/
EXPORT int f_SkinWhite(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio);
EXPORT void f_AffinetransformMetrixCompute(float x1, float y1, float x2, float y2, float x3, float y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float hMatrix[6]);
/*************************************************************************
*Function: SKIN WHITE USING CURVE
*Function: getWHFromHMatrix
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*belta: intensity of curve enhancement,range[2,10],default:2
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
*Reference: "A Two-Stage Contrast Enhancement Algorithm for Digital Images"
*width: source image width
*height: source image height
*H: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*wh: the size of image outputs, wh[0]=dWidth, wh[1] = dHeight
*Return: NULL
**************************************************************************/
EXPORT int f_SkinWhiteCurve(unsigned char* srcData, int width, int height, int stride, int belta, int ratio);
EXPORT void getWHFromHMatrix(int width, int height, float H[6], int wh[2]);
/*************************************************************************
*Function: SKIN WHITE USING SMOOTH LIGHT OF PS
*Function: Affinetransfrom
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*H: affinetransfrom matrix,[a11, a12, b1, a21, a22, b2]
*dstData: output image buffer with format bgra32
*dWidth: width of image outputs
*dHeight: height of image outputs
*dStride: Stride of image outputs
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_SkinWhitePS(unsigned char* srcData, int width, int height, int stride, int ratio);
EXPORT int f_AffineTransform(unsigned char* srcData, int width, int height, int stride, float H[6], unsigned char* dstData, int dWidth, int dHeight, int dStride);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_SkinWhite(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio);
int f_SkinWhiteCurve(unsigned char* srcData, int width, int height, int stride, int belta, int ratio);
int f_SkinWhitePS(unsigned char* srcData, int width, int height, int stride, int ratio);
int f_AffineTransform(unsigned char* srcData, int width, int height, int stride, float H[6], unsigned char* dstData, int dWidth, int dHeight, int dStride);
void getWHFromHMatrix(int width, int height, float H[6], int wh[2]);
void f_AffinetransformMetrixCompute(float x1, float y1, float x2, float y2, float x3, float y3, float tx1, float ty1, float tx2, float ty2, float tx3, float ty3, float hMatrix[6]);
#ifdef __cplusplus
}
#endif
......
#include"f_BeautyCamera.h"
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"f_GaussFilter.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h" //3.10
#include "f_SkinWhite.h"
//#include"disabled/f_SkinDetect.h"//3.9
#include"f_Commen_MixLayer.h"
#include"f_LaplaceSharpen.h"
#include"f_SurfaceBlur.h"
#include "iostream"
#include <iostream>
#include <opencv2/opencv.hpp>
#include "Poco/Stopwatch.h"
#include <omp.h>
using namespace std;
using namespace cv;
/*************************************************************************
*Function: Smart Blur
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*curveMap: light curve lut, 512x512
*softRatio: intensity of softskin, [0,100]
*skinWhiteRatio: intensity of skin white, [0,100]
*skinColorRatio: intensity of skin color, [-50,50]
*sharpenRatio: intensity of sharpen, [0, 100],default 30
*Return: 0-OK,other failed
**************************************************************************/
#include <stdlib.h>
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef ClampToByte
#define ClampToByte(v) (((unsigned)(int)(v)) <(255) ? (v) : (v < 0) ? (0) : (255))
#endif
#include <xmmintrin.h>
unsigned int skinDetection(unsigned char *rgb_src, int width, int height, int channels) {
int stride = width * channels;
int lastCol = width * channels - channels;
int lastRow = height * stride - stride;
unsigned int sum = 0;
// #pragma omp parallel for
for (int y = 0; y < height; ++y) {
int cur_row = stride * y;
int next_row = min(cur_row + stride, lastRow);
unsigned char *next_scanLine = rgb_src + next_row;
unsigned char *cur_scanLine = rgb_src + cur_row;
// #pragma omp parallel for
for (int x = 0; x < width; ++x) {
int cur_col = x * channels;
int next_col = min(cur_col + channels, lastCol);
unsigned char *c00 = cur_scanLine + cur_col;
unsigned char *c10 = cur_scanLine + next_col;
unsigned char *c01 = next_scanLine + cur_col;
unsigned char *c11 = next_scanLine + next_col;
unsigned char r_avg = ((c00[0] + c10[0] + c01[0] + c11[0])) >> 2;
unsigned char g_avg = ((c00[1] + c10[1] + c01[1] + c11[1])) >> 2;
unsigned char b_avg = ((c00[2] + c10[2] + c01[2] + c11[2])) >> 2;
if (r_avg >= 60 && g_avg >= 40 && b_avg >= 20 && r_avg >= b_avg && (r_avg - g_avg) >= 10 &&
max(max(r_avg, g_avg), b_avg) - min(min(r_avg, g_avg), b_avg) >= 10) {
++sum;
}
}
}
return sum;
}
void skinFilter(unsigned char *input, unsigned char *output, int width, int height, int channels) {
int stride = width * channels;
int lastCol = width * channels - channels;
int lastRow = height * stride - stride;
for (int y = 0; y < height; ++y) {
int cur_row = stride * y;
int next_row = min(cur_row + stride, lastRow);
unsigned char *next_scanOutLine = output + next_row;
unsigned char *cur_scanOutLine = output + cur_row;
unsigned char *scanOutLine = output + y * stride;
unsigned char *scanInLine = input + y * stride;
for (int x = 0; x < width; ++x) {
int cur_col = x * channels;
int next_col = min(cur_col + channels, lastCol);
unsigned char *c00 = cur_scanOutLine + cur_col;
unsigned char *c10 = cur_scanOutLine + next_col;
unsigned char *c01 = next_scanOutLine + cur_col;
unsigned char *c11 = next_scanOutLine + next_col;
int r_avg = ((c00[0] + c10[0] + c01[0] + c11[0])) >> 2;
int g_avg = ((c00[1] + c10[1] + c01[1] + c11[1])) >> 2;
int b_avg = ((c00[2] + c10[2] + c01[2] + c11[2])) >> 2;
int is_skin = !(r_avg >= 60 && g_avg >= 40 && b_avg >= 20 && r_avg >= b_avg && (r_avg - g_avg) >= 10 &&
max(max(r_avg, g_avg), b_avg) - min(min(r_avg, g_avg), b_avg) >= 10);
if (is_skin)
for (int c = 0; c < channels; ++c)
scanOutLine[c] = scanInLine[c];
scanOutLine += channels;
scanInLine += channels;
}
}
}
void getOffsetPos(int *offsetPos, int length, int left, int right, int step) {
if (offsetPos == NULL) return;
if ((length < 0) || (left < 0) || (right < 0))
return;
for (int x = -left; x < length + right; ++x) {
int pos = x;
int length2 = length + length;
if (pos < 0) {
do {
pos += length2;
} while (pos < 0);
} else if (pos >= length2) {
do {
pos -= length2;
} while (pos >= length2);
}
if (pos >= length)
pos = length2 - 1 - pos;
offsetPos[x + left] = pos * step;
}
}
void skinDenoise(unsigned char *input, unsigned char *output, int width, int height, int channels, int radius,
int smoothingLevel) {
if ((input == NULL) || (output == NULL)) return;
if ((width <= 0) || (height <= 0)) return;
if ((radius <= 0) || (smoothingLevel <= 0)) return;
if ((channels != 1) && (channels != 3)) return;
int windowSize = (2 * radius + 1) * (2 * radius + 1);
int *colPower = (int *) malloc(width * channels * sizeof(int));
int *colValue = (int *) malloc(width * channels * sizeof(int));
int *rowPos = (int *) malloc((width + radius + radius) * channels * sizeof(int));
int *colPos = (int *) malloc((height + radius + radius) * channels * sizeof(int));
if ((colPower == NULL) || (colValue == NULL) || (rowPos == NULL) || (colPos == NULL)) {
if (colPower) free(colPower);
if (colValue) free(colValue);
if (rowPos) free(rowPos);
if (colPos) free(colPos);
return;
}
int stride = width * channels;
int smoothLut[256] = {0};
float ii = 0.f;
for (int i = 0; i <= 255; i++, ii -= 1.) {
smoothLut[i] = (int) ((expf(ii * (1.0f / (smoothingLevel * 255.0f))) + (smoothingLevel * (i + 1)) + 1) * 0.5f);
smoothLut[i] = max(smoothLut[i], 1);
}
getOffsetPos(rowPos, width, radius, radius, channels);
getOffsetPos(colPos, height, radius, radius, stride);
int *rowOffset = rowPos + radius;
int *colOffSet = colPos + radius;
for (int y = 0; y < height; ++y) {
unsigned char *scanInLine = input + y * stride;
unsigned char *scanOutLine = output + y * stride;
if (y == 0) {
for (int x = 0; x < stride; x += channels) {
int colSum[3] = {0};
int colSumPow[3] = {0};
for (int z = -radius; z <= radius; ++z) {
unsigned char *sample = input + colOffSet[z] + x;
for (int c = 0; c < channels; ++c) {
colSum[c] += sample[c];
colSumPow[c] += sample[c] * sample[c];
}
}
for (int c = 0; c < channels; ++c) {
colValue[x + c] = colSum[c];
colPower[x + c] = colSumPow[c];
}
}
} else {
unsigned char *lastCol = input + colOffSet[y - radius - 1];
unsigned char *nextCol = input + colOffSet[y + radius];
for (int x = 0; x < stride; x += channels) {
for (int c = 0; c < channels; ++c) {
colValue[x + c] -= lastCol[x + c] - nextCol[x + c];
colPower[x + c] -= lastCol[x + c] * lastCol[x + c] - nextCol[x + c] * nextCol[x + c];
}
}
}
int prevSum[3] = {0};
int prevPowerSum[3] = {0};
for (int z = -radius; z <= radius; ++z) {
int index = rowOffset[z];
for (int c = 0; c < channels; ++c) {
prevSum[c] += colValue[index + c];
prevPowerSum[c] += colPower[index + c];
}
}
for (int c = 0; c < channels; ++c) {
const int mean = prevSum[c] / windowSize;
const int diff = mean - scanInLine[c];
const int edge = ClampToByte(diff);
const int masked_edge = (edge * scanInLine[c] + (256 - edge) * mean) >> 8;
const int var = (prevPowerSum[c] - mean * prevSum[c]) / windowSize;
const int out = masked_edge - diff * var / (var + smoothLut[scanInLine[c]]);
scanOutLine[c] = ClampToByte(out);
}
scanInLine += channels;
scanOutLine += channels;
for (int x = 1; x < width; ++x) {
int lastRow = rowOffset[x - radius - 1];
int nextRow = rowOffset[x + radius];
for (int c = 0; c < channels; ++c) {
prevSum[c] = prevSum[c] - colValue[lastRow + c] + colValue[nextRow + c];
prevPowerSum[c] = prevPowerSum[c] - colPower[lastRow + c] + colPower[nextRow + c];
const int mean = prevSum[c] / windowSize;
const int diff = mean - scanInLine[c];
const int edge = ClampToByte(diff);
const int masked_edge = (edge * scanInLine[c] + (256 - edge) * mean) >> 8;
const int var = (prevPowerSum[c] - mean * prevSum[c]) / windowSize;
const int out = masked_edge - diff * var / (var + smoothLut[scanInLine[c]]);
scanOutLine[c] = ClampToByte(out);
}
scanInLine += channels;
scanOutLine += channels;
}
}
if (colPower) free(colPower);
if (colValue) free(colValue);
if (rowPos) free(rowPos);
if (colPos) free(colPos);
}
void skinSmoothing(unsigned char *input, unsigned char *output, int width, int height, int channels,
int smoothingLevel, int apply_skin_filter) {
if (input == NULL || output == NULL || width == 0 || height == 0 || channels == 1)
return;
//1.detect skin color, adapt radius according to skin color ratio
unsigned int skinSum = skinDetection(input, width, height, channels);
float skin_rate = skinSum / (float) (width * height) * 100;
int radius = min(width, height) / skin_rate + 1;
//2.perform edge detection to obtain a edge map && smoothing level for apply skin denoise
skinDenoise(input, output, width, height, channels, radius, smoothingLevel);
//3.re-detect skin color based on the denoise results, filtered non-skin areas
if (apply_skin_filter)
skinFilter(input, output, width, height, channels);
}
int main2(int argc, char* argv[]){
Poco::Stopwatch stopwatch;
string filePath = string(argv[1]);
int softRatio = stoi(string(argv[2]));
int apply_skin_filter = stoi(string(argv[3]));
int skinWhiteRatio = stoi(string(argv[4]));
int sharpenRatio = stoi(string(argv[5]));
int skinColorRatio = 100;
Mat srcImage = imread(filePath);
if (!srcImage.data) {
std::cout << "Image not loaded";
return -1;
}
cout << "读取图片耗时:" << (int)(stopwatch.elapsed()/1000) << endl;
cout << srcImage.size << endl;
cout << srcImage.channels() << endl;
cout << srcImage.cols << endl;
cout << srcImage.rows << endl;
cout << srcImage.total() << endl;
stopwatch.start();
cv::cvtColor(srcImage,srcImage,cv::COLOR_BGR2RGB);
// for(int i=0;i<9;++i){
// printf("srcImage.data[%d] = %d\n",i,(int)srcImage.data[i]);
// }
int channels = 3;
unsigned char *output = (unsigned char *) calloc(srcImage.cols * channels * srcImage.rows * sizeof(unsigned char), 1);
int smoothingLevel = softRatio;
skinSmoothing(srcImage.data, output,srcImage.cols, srcImage.rows,channels, smoothingLevel, apply_skin_filter);
cout << "磨皮图片耗时:" << (int)(stopwatch.elapsed()/1000) << endl;
// saveImage(out_file, width, height, channels, output);
// free(output);
srcImage.data = output;
cv::cvtColor(srcImage,srcImage,cv::COLOR_RGB2BGR);
// imshow("[img Dst]", srcImage);
// imwrite("tongshi_out.png",srcImage);
// waitKey(0);
int res = f_BeautyCamera(srcImage.data,srcImage.cols,srcImage.rows,srcImage.cols*srcImage.channels(),softRatio,skinWhiteRatio,skinColorRatio,sharpenRatio);
cout << "处理图片耗时:" << (int)(stopwatch.elapsed()/1000) << endl;
// int res = f_SkinWhitePS(srcImage.data,srcImage.cols,srcImage.rows,srcImage.cols*srcImage.channels(),skinWhiteRatio);
// int res = f_SkinWhiteCurve(srcImage.data,srcImage.cols,srcImage.rows,srcImage.cols*srcImage.channels(),10,skinWhiteRatio);
imshow("[img Dst]", srcImage);
// imwrite("tongshi_out.png",srcImage);
waitKey(0);
free(output);
return 0;
}
int f_BeautyCamera_old(unsigned char* srcData, int width, int height, int stride, unsigned char* curveMap, int softRatio, int skinWhiteRatio, int skinColorRatio, int sharpenRatio)
{
//softskin with channel method
int ret = 0;
unsigned char* greenData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* gaussData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* curveData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* skinData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* pSrc = srcData;
unsigned char* pGreen = greenData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pGreen[0] = pSrc[0];
pGreen[1] = pSrc[0];
pGreen[2] = pSrc[0];
pSrc += 4;
pGreen += 4;
}
}
memcpy(gaussData, greenData, sizeof(unsigned char) * height * stride);
memcpy(curveData, srcData, sizeof(unsigned char) * height * stride);
ret = f_LUTFilter(curveData, width, height, stride, curveMap);
float hpRadius = 10.0f * width * height / (594 * 677);
ret = f_FastGaussFilter(gaussData, width, height, stride,hpRadius);
pSrc = srcData;
pGreen = greenData;
unsigned char* pCurve = curveData;
unsigned char* pGauss = gaussData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int t;
t = CLIP3(pGauss[0] - pGreen[0] + 128, 0, 255);
t = ModeSuperposition(t, t);
t = ModeSuperposition(t, t);
t = t * 220 / 255;
pGreen[0] = CLIP3((pCurve[0] * t + (255 - t) * pSrc[0]) / 255, 0, 255);
pGreen[1] = CLIP3((pCurve[1] * t + (255 - t) * pSrc[1]) / 255, 0, 255);
pGreen[2] = CLIP3((pCurve[2] * t + (255 - t) * pSrc[2]) / 255, 0, 255);
pGreen += 4;
pGauss += 4;
pSrc += 4;
pCurve += 4;
}
}
memcpy(skinData, greenData, sizeof(unsigned char) * height * stride);
int maskSmoothRadius = 10;//3 * width * height / (594 * 677);
ret = f_SkinPDF(skinData, width, height, stride);
ret = f_FastGaussFilter(skinData, width, height, stride, maskSmoothRadius);
if(softRatio != 0)
{
pGauss = skinData;
pSrc = srcData;
pGreen = greenData;
int k = softRatio * 128 / 100;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int mask = (pGauss[0] + pGauss[1] + pGauss[2]) / 3;
int tb = CLIP3((pSrc[0] * (255 - mask) + pGreen[0] * mask) / 255, 0, 255);
int tg = CLIP3((pSrc[1] * (255 - mask) + pGreen[1] * mask) / 255, 0, 255);
int tr = CLIP3((pSrc[2] * (255 - mask) + pGreen[2] * mask) / 255, 0, 255);
pSrc[0] = CLIP3((pSrc[0] * (128 - k) + tb * k) >> 7, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (128 - k) + tg * k) >> 7, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (128 - k) + tr * k) >> 7, 0, 255);
pSrc += 4;
pGauss += 4;
pGreen += 4;
}
}
}
//skin white
if(skinWhiteRatio != 0)
{
unsigned char lightMap[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 56, 58, 60, 62, 64, 66, 69, 71, 74, 76, 78, 80, 82, 84, 85, 87, 88, 90, 92, 93, 94, 96, 97, 99, 100, 102, 104, 105, 106, 108, 109, 111, 113, 115, 116, 118, 120, 122, 124, 127, 129, 131, 133, 136, 138, 139, 141, 142, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 175, 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 200, 201, 202, 203, 203, 204, 205, 206, 206, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 252, 252, 253, 254, 255};
pSrc = srcData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pSrc[0] = CLIP3((pSrc[0] * (100 - skinWhiteRatio) + lightMap[pSrc[0]] * skinWhiteRatio) / 100, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (100 - skinWhiteRatio) + lightMap[pSrc[1]] * skinWhiteRatio) / 100, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (100 - skinWhiteRatio) + lightMap[pSrc[2]] * skinWhiteRatio) / 100, 0, 255);
pSrc += 4;
}
}
}
//skin color
if(skinColorRatio != 0)
{
unsigned char coldMap_b[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 62, 63, 65, 67, 69, 70, 72, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 93, 95, 96, 97, 98, 99, 100, 101, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 159, 160, 161, 162, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 211, 211, 212, 212, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 236, 237, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
unsigned char coldMap_g[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 54, 55, 56, 57, 58, 60, 62, 62, 62, 64, 65, 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 208, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235, 237, 238, 238, 239, 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255};
unsigned char coldMap_r[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 58, 58, 59, 61, 62, 64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 139, 140, 141, 142, 143, 144, 145, 146, 147, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 205, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 233, 234, 235, 236, 238, 239, 240, 241, 242, 243, 243, 244, 245, 246, 247, 248, 250, 251, 252, 253, 254, 255};
unsigned char warmMap_g[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 93, 94, 95, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 117, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 174, 175, 176, 177, 178, 179, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 209, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 227, 229, 230, 231, 232, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
unsigned char warmMap_b[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 58, 59, 60, 61, 61, 63, 64, 65, 64, 65, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 86, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 108, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 133, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158, 159, 160, 163, 164, 165, 166, 168, 168, 169, 170, 171, 172, 173, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 206, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 218, 219, 220, 221, 222, 223, 226, 226, 227, 228, 229, 230, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 242, 243, 242, 243, 244, 245, 246, 247, 250, 251, 252, 253, 254, 255};
unsigned char warmMap_r[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 65, 66, 67, 68, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 102, 103, 104, 106, 107, 108, 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 124, 125, 126, 126, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 181, 181, 182, 183, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 225, 226, 227, 228, 229, 230, 231, 231, 230, 230, 231, 233, 233, 234, 235, 236, 237, 238, 239, 240, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
pSrc = srcData;
if(skinColorRatio < 0)
{
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int k = -skinColorRatio;
pSrc[0] = CLIP3((pSrc[0] * (50 - k) + coldMap_b[pSrc[0]] * k) / 50, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (50 - k) + coldMap_g[pSrc[1]] * k) / 50, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (50 - k) + coldMap_r[pSrc[2]] * k) / 50, 0, 255);
pSrc += 4;
pGreen += 4;
}
}
}
else
{
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int k = skinColorRatio;
pSrc[0] = CLIP3((pSrc[0] * (50 - k) + warmMap_b[pSrc[0]] * k) / 50, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (50 - k) + warmMap_g[pSrc[1]] * k) / 50, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (50 - k) + warmMap_r[pSrc[2]] * k) / 50, 0, 255);
pSrc += 4;
pGreen += 4;
}
}
}
}
//laplace sharpen
memcpy(greenData, srcData,sizeof(unsigned char) * height * stride);
f_LaplaceSharpen(greenData, width, height, stride, 0);
pSrc = srcData;
pGreen = greenData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pSrc[0] = CLIP3((pSrc[0] * (100 - sharpenRatio) + pGreen[0] * sharpenRatio) / 100, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (100 - sharpenRatio) + pGreen[1] * sharpenRatio) / 100, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (100 - sharpenRatio) + pGreen[2] * sharpenRatio) / 100, 0, 255);
pSrc += 4;
pGreen += 4;
}
}
free(gaussData);
free(greenData);
free(curveData);
free(skinData);
return 0;
};
/*************************************************************************
*Function: Beauty camera advanced softskin effect, data:20190930
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*softRatio: intensity of softskin, [0,100]
*skinWhiteRatio: intensity of skin white, [0,100]
*skinColorRatio: intensity of skin color, [-50,50]
*sharpenRatio: intensity of sharpen, [0, 100],default 30
*Return: 0-OK,other failed
**************************************************************************/
int f_BeautyCamera(unsigned char* srcData, int width, int height, int stride, int softRatio, int skinWhiteRatio, int skinColorRatio, int sharpenRatio)
{
int ret = 0;
int length = stride * height;
// unsigned char* greenData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* greenData = (unsigned char*)malloc(sizeof(unsigned char) * length);
// unsigned char* smoothData = (unsigned char*)malloc(sizeof(unsigned char) * length);
// unsigned char* hpData = (unsigned char*)malloc(sizeof(unsigned char) * length);
// unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
// memcpy(smoothData, srcData, sizeof(unsigned char) * length);
unsigned char* pGreen = greenData;
// int smoothRadius = 8;
// int smoothThreshold = 38;
// int maskSmoothRadius = 3;
// ret = f_SurfaceBlur(smoothData, width, height, stride, smoothRadius, smoothThreshold);
// memcpy(skinPDF, smoothData, sizeof(unsigned char) * length);
// ret = f_SkinPDF(skinPDF, width, height, stride);
// ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
// unsigned char* pSkin = skinPDF;
// unsigned char* pSmooth = smoothData;
// unsigned char* pHP = hpData;
// int k = softRatio * 128 / 200;
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// pHP[0] = CLIP3(pSmooth[0] - pSrc[0] + 128, 0, 255);
// pHP[1] = CLIP3(pSmooth[1] - pSrc[1] + 128, 0, 255);
// pHP[2] = CLIP3(pSmooth[2] - pSrc[2] + 128, 0, 255);
// pGreen[0] = pSrc[0];
// pGreen[1] = pSrc[1];
// pGreen[2] = pSrc[2];
// pGreen += 3;
// pHP += 3;
// pSmooth += 3;
// pSrc += 3;
// }
// }
// float textureRatio = 40;
// float hpRadius = 3.5f * textureRatio / 100.0f;
// ret = f_FastGaussFilter(hpData, width, height, stride, hpRadius);
// pSmooth = smoothData;
// pHP = hpData;
// pSrc = srcData;
// if(softRatio != 0)
// {
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// int hpb = pHP[0];
// int hpg = pHP[1];
// int hpr = pHP[2];
// hpb = ModeLinearLight(pSrc[0], hpb);
// hpg = ModeLinearLight(pSrc[1], hpg);
// hpr = ModeLinearLight(pSrc[2], hpr);
// int mask = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
// hpb = CLIP3((hpb * mask + pSmooth[0] * (255 - mask)) / 255, 0, 255);
// hpg = CLIP3((hpg * mask + pSmooth[1] * (255 - mask)) / 255, 0, 255);
// hpr = CLIP3((hpr * mask + pSmooth[2] * (255 - mask)) / 255, 0, 255);
// pSrc[0] = CLIP3((hpb * k + pSrc[0] * (128 - k)) >> 7, 0, 255);
// pSrc[1] = CLIP3((hpg * k + pSrc[1] * (128 - k)) >> 7, 0, 255);
// pSrc[2] = CLIP3((hpr * k + pSrc[2] * (128 - k)) >> 7, 0, 255);
// pSrc += 3;
// pHP += 3;
// pSmooth += 3;
// pSkin += 3;
// }
// }
// }
//skin white
if(skinWhiteRatio != 0)
{
unsigned char lightMap[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 56, 58, 60, 62, 64, 66, 69, 71, 74, 76, 78, 80, 82, 84, 85, 87, 88, 90, 92, 93, 94, 96, 97, 99, 100, 102, 104, 105, 106, 108, 109, 111, 113, 115, 116, 118, 120, 122, 124, 127, 129, 131, 133, 136, 138, 139, 141, 142, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 175, 176, 177, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 200, 201, 202, 203, 203, 204, 205, 206, 206, 207, 208, 209, 209, 210, 211, 211, 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 252, 252, 253, 254, 255};
pSrc = srcData;
for(int j = 0; j < height; ++j)
{
for(int i = 0; i < width; ++i)
{
pSrc[0] = CLIP3((pSrc[0] * (100 - skinWhiteRatio) + lightMap[pSrc[0]] * skinWhiteRatio) / 100, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (100 - skinWhiteRatio) + lightMap[pSrc[1]] * skinWhiteRatio) / 100, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (100 - skinWhiteRatio) + lightMap[pSrc[2]] * skinWhiteRatio) / 100, 0, 255);
pSrc += 3;
}
}
}
//skin color
// if(skinColorRatio != 0)
// {
// unsigned char coldMap_b[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 56, 57, 58, 59, 60, 62, 63, 65, 67, 69, 70, 72, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 93, 95, 96, 97, 98, 99, 100, 101, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 159, 160, 161, 162, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 211, 211, 212, 212, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 236, 237, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
// unsigned char coldMap_g[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 54, 55, 56, 57, 58, 60, 62, 62, 62, 64, 65, 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 208, 208, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235, 237, 238, 238, 239, 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255};
// unsigned char coldMap_r[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 58, 58, 59, 61, 62, 64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 139, 140, 141, 142, 143, 144, 145, 146, 147, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 175, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 205, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 233, 234, 235, 236, 238, 239, 240, 241, 242, 243, 243, 244, 245, 246, 247, 248, 250, 251, 252, 253, 254, 255};
//
// unsigned char warmMap_g[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 93, 94, 95, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 117, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 174, 175, 176, 177, 178, 179, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 209, 209, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 227, 229, 230, 231, 232, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
// unsigned char warmMap_b[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 58, 59, 60, 61, 61, 63, 64, 65, 64, 65, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 86, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 108, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 133, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141, 142, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158, 159, 160, 163, 164, 165, 166, 168, 168, 169, 170, 171, 172, 173, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 206, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 218, 219, 220, 221, 222, 223, 226, 226, 227, 228, 229, 230, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 242, 243, 242, 243, 244, 245, 246, 247, 250, 251, 252, 253, 254, 255};
// unsigned char warmMap_r[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 65, 66, 67, 68, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100, 102, 103, 104, 106, 107, 108, 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 124, 125, 126, 126, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 181, 181, 182, 183, 182, 183, 184, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 225, 226, 227, 228, 229, 230, 231, 231, 230, 230, 231, 233, 233, 234, 235, 236, 237, 238, 239, 240, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
// pSrc = srcData;
// if(skinColorRatio < 0)
// {
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// int k = -skinColorRatio;
// pSrc[0] = CLIP3((pSrc[0] * (50 - k) + coldMap_b[pSrc[0]] * k) / 50, 0, 255);
// pSrc[1] = CLIP3((pSrc[1] * (50 - k) + coldMap_g[pSrc[1]] * k) / 50, 0, 255);
// pSrc[2] = CLIP3((pSrc[2] * (50 - k) + coldMap_r[pSrc[2]] * k) / 50, 0, 255);
// pSrc += 3;
// pGreen += 3;
// }
// }
// }
// else
// {
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// int k = skinColorRatio;
// pSrc[0] = CLIP3((pSrc[0] * (50 - k) + warmMap_b[pSrc[0]] * k) / 50, 0, 255);
// pSrc[1] = CLIP3((pSrc[1] * (50 - k) + warmMap_g[pSrc[1]] * k) / 50, 0, 255);
// pSrc[2] = CLIP3((pSrc[2] * (50 - k) + warmMap_r[pSrc[2]] * k) / 50, 0, 255);
// pSrc += 3;
// pGreen += 3;
// }
// }
// }
// }
//laplace sharpen
memcpy(greenData, srcData,sizeof(unsigned char) * height * stride);
f_LaplaceSharpen(greenData, width, height, stride, 0);
pSrc = srcData;
pGreen = greenData;
for(int j = 0; j < height; ++j)
{
for(int i = 0; i < width; ++i)
{
pSrc[0] = CLIP3((pSrc[0] * (100 - sharpenRatio) + pGreen[0] * sharpenRatio) / 100, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (100 - sharpenRatio) + pGreen[1] * sharpenRatio) / 100, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (100 - sharpenRatio) + pGreen[2] * sharpenRatio) / 100, 0, 255);
pSrc += 3;
pGreen += 3;
}
}
// free(skinPDF);
// free(smoothData);
// free(hpData);
free(greenData);
return ret = 0;
};
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-4-23
Mail: dongtingyueh@163.com
Description: BeautyCamera .
Refference: None
*************************************************************************/
#ifndef __T_BEAUTY_CAMERA__
#define __T_BEAUTY_CAMERA__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: Smart Blur
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*softRatio: intensity of softskin, [0,100]
*skinWhiteRatio: intensity of skin white, [0,100]
*skinColorRatio: intensity of skin color, [-50,50]
*sharpenRatio: intensity of sharpen, [0, 100],default 30
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_BeautyCamera(unsigned char* srcData, int width, int height, int stride, int softRatio, int skinWhiteRatio, int skinColorRatio, int sharpenRatio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_BeautyCamera(unsigned char* srcData, int width, int height, int stride, int softRatio, int skinWhiteRatio, int skinColorRatio, int sharpenRatio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"Commen.h"
#include"f_BeautyIris.h"
#include"TRGB2YUV.h"
#include"f_MeanFilter.h"
#include"iostream"
#include <opencv2/opencv.hpp>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <Poco/URI.h>
#include <Poco/StreamCopier.h>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTMLForm.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/NetException.h>
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/StreamCopier.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/JSON/Query.h"
#include "Poco/JSON/PrintHandler.h"
#include <Poco/Stopwatch.h>
#include "Poco/URIStreamOpener.h"
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/SharedPtr.h"
#include "Poco/Exception.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/SSLException.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/FilePartSource.h"
#include "vector"
using namespace dlib;
using namespace cv;
using namespace std;
using namespace Poco;
using namespace Poco::Net;
//void RGB2HSB(unsigned char r, unsigned char g, unsigned char b, float *H, float *S, float* B)
//{
// int max = MAX2(r, MAX2(g, b));
// int min = MIN2(r, MIN2(g, b));
// int temp[3] = {min, r + g + b - max - min, max};
// int maxIndex = 0, minIndex = 0;
// int rgb[3] = {r, g, b};
// for(int i=0;i<3;i++) {
// if(temp[0]==rgb[i]) minIndex=i;
// if(temp[2]==rgb[i]) maxIndex=i;
// }
// *B = temp[2] / 255.0f;
// *S = 1.0f - (float)temp[0] / temp[2];
// *H = maxIndex * 120.0f + 60.0f * (temp[1] / *S / temp[2] + (1.0f - 1.0f / *S)) * ((maxIndex - minIndex + 3) % 3 == 1 ? 1 : -1);
// *H = (int)(*H + 360) % 360;
//}
//void HSB2RGB(float H, float S, float B, unsigned char* r, unsigned char* g, unsigned char* b)
//{
// float rgb[3] = {0};
// for(int offset = 240, i = 0; i < 3; i++, offset -= 120)
// {
// float x = abs((int)(H + offset) % 360 - 240);
// if(x <= 60) rgb[i] = 255;
// else if(x > 60 && x < 120) rgb[i] = ((1.0f - (x - 60) / 60.0f) * 255.0f);
// else rgb[i] = 0;
// }
// rgb[0] += (255 - rgb[0]) * (1.0f - S);
// rgb[1] += (255 - rgb[1]) * (1.0f - S);
// rgb[2] += (255 - rgb[2]) * (1.0f - S);
//
// rgb[0] *= B;
// rgb[1] *= B;
// rgb[2] *= B;
// *r = CLIP3(rgb[0], 0, 255);
// *g = CLIP3(rgb[1], 0, 255);
// *b = CLIP3(rgb[2], 0, 255);
//}
bool f_PNPoly_OPT(int xPoint[],int yPoint[],int pointNum,int x, int y, int minX, int minY, int maxX, int maxY)
{
if(x < minX || x > maxX || y < minY || y > maxY)
return false;
int i, j, c = 0;
for(i = 0, j = pointNum - 1; i < pointNum; j = i++)
{
if((float)((yPoint[i] > y) != (yPoint[j] > y)) && (x < (float)(xPoint[j] - xPoint[i]) * (y - yPoint[i]) / (yPoint[j] - yPoint[i]) + xPoint[i]))
c = !c;
}
return c;
}
/************************************************************
*Function: f_PNPoly
*Description: Point in the poly or not
*Params:
*xPoint: x position or several points input.
*yPoint: y position or several points input.
*pointNum :number of points input.
*(x,y): the current position.
*Return :true or false.
************************************************************/
bool f_PNPoly(int xPoint[],int yPoint[],int pointNum,int x, int y)
{
int i, j, c = 0;
for(i = 0, j = pointNum - 1; i < pointNum; j = i++)
{
if((float)((yPoint[i] > y) != (yPoint[j] > y)) && (x < (float)(xPoint[j] - xPoint[i]) * (y - yPoint[i]) / (yPoint[j] - yPoint[i]) + xPoint[i]))
c = !c;
}
return c;
}
/************************************************************
*Function: Beauty Iris
*Description: Beauty Iris process
*Params:
*srcData: image bgra data
*width :image width
*height :image height
*stride :image stride
*srcPoints: 13 points of 101 face points.
*maskData: iris mask data
*mWidth: width of mask.
*mHeight: height of mask.
*mStride: stride of mask.
maskPoints: center point of mask.
*ratio: intensity of beauty iris, [0, 100].
*Return :0-OK,or failed
************************************************************/
int f_BeautyIris(unsigned char* srcData, int width, int height, int stride, int srcPoints[], unsigned char* maskData, int mWidth, int mHeight, int mStride, int maskPoints[], int ratio,int eye_pupil_radius,int eye_pupil_center_x,int eye_pupil_center_y,float irisRadiusExpand=1.0)
{
int ret = 0;
int cenx = eye_pupil_center_x;
int ceny = eye_pupil_center_y;
//compute iris radius.
// int eyedistance = sqrt((float)(srcPoints[2 * 0] - srcPoints[2 * 5]) * (srcPoints[2 * 0] - srcPoints[2 * 5]) + (srcPoints[2 * 0 + 1] - srcPoints[2 * 5 + 1]) * (srcPoints[2 * 0 + 1] - srcPoints[2 * 5 + 1])) / 2;
int irisRadius = eye_pupil_radius;
irisRadius*=irisRadiusExpand;
//compute the rectangle of eye area.
int px = CLIP3(cenx - irisRadius, 0, width - 1);
int py = CLIP3(ceny - irisRadius, 0, height - 1);
int pmaxX = CLIP3(cenx + irisRadius, 0, width - 1);
int pmaxY = CLIP3(ceny + irisRadius, 0, height - 1);
int w = pmaxX - px + 2;
int h = pmaxY - py + 2;
const int pointNum = 63;
int xPoints[pointNum];
int yPoints[pointNum];
int maxX = 0, minX = 100000, maxY = 0, minY = 100000;
for(int i = 0; i < pointNum; i++)
{
xPoints[i] = srcPoints[2 * i];
yPoints[i] = srcPoints[2 * i + 1];
maxX = MAX2(srcPoints[2 * i], maxX);
maxY = MAX2(srcPoints[2 * i + 1], maxY);
minX = MIN2(srcPoints[2 * i], minX);
minY = MIN2(srcPoints[2 * i + 1], minY);
}
//irisMask feather process
unsigned char* irisMask = (unsigned char*)malloc(sizeof(unsigned char) * w * h * 3);
unsigned char* pMask = irisMask;
for(int j = 0; j < h; j++)
{
for(int i = 0; i < w; i++)
{
int dis = sqrt((float)(i - irisRadius) * (i - irisRadius) + (j - irisRadius) * (j - irisRadius));
if(dis <= irisRadius*irisRadiusExpand&&f_PNPoly_OPT(xPoints, yPoints, pointNum, i + px, j + py, minX, minY, maxX, maxY))
// if(dis <= irisRadius)
pMask[0] = pMask[1] = pMask[2] = 255;
else
pMask[0] = pMask[1] = pMask[2] = 0;
pMask += 3;
}
}
// Mat m;
// m.create(h,w,CV_8UC(3));
// m.data = irisMask;
// imshow("irisMask",m);
// waitKey(0);
// f_FastMeanFilter(irisMask, w, h, w * 3, 3);
//
// pMask = irisMask;
// for(int j = 0; j < h; j++)
// {
// for(int i = 0; i < w; i++)
// {
// if(pMask[0] > 128)
// pMask[0] = pMask[1] = pMask[2] = 255;
// else
// pMask[0] = pMask[1] = pMask[2] = 0;
// pMask += 3;
// }
// }
// f_FastMeanFilter(irisMask, w, h, w * 3, 3);
// Mat m;
// m.create(h,w,CV_8UC(3));
// m.data = irisMask;
// imshow("irisMask",m);
// waitKey(0);
//beauty iris process
pMask = irisMask;
for(int j = 0; j < h; j++)
{
for(int i = 0; i < w; i++)
{
if((pMask[0] + pMask[1] + pMask[2]) / 3 > 0)
{
int pos_src = (px + i) * 3 + (py + j) * stride;
int mx = i * mWidth / w;
int my = j * mHeight / h;
int pos_mask = mx * 3 + my * mStride;
int r = srcData[pos_src + 2];
int g = srcData[pos_src + 1];
int b = srcData[pos_src];
int mr = maskData[pos_mask + 2];
int mg = maskData[pos_mask + 1];
int mb = maskData[pos_mask];
int Y, U, V, mY, mU, mV;
//YUV
RGB2YUV(r, g, b,&Y, &U, &V);
RGB2YUV(mr, mg, mb, &mY, &mU, &mV);
unsigned char R, G, B;
YUV2RGB(Y, mU, mV, &R, &G, &B);
//feather mask process
int a = (pMask[0] + pMask[1] + pMask[2]) / 3;
// B = CLIP3((b * (255 - a) + B * a) >> 8, 0, 255);
// G = CLIP3((g * (255 - a) + G * a) >> 8, 0, 255);
// R = CLIP3((r * (255 - a) + R * a) >> 8, 0, 255);
// //YUV color correct
// a = CLIP3((r + g + b) / 3 * 2, 0, 255);
// R = (R * a + r * (255 - a)) / 255;
// G = (G * a + g * (255 - a)) / 255;
// B = (B * a + b * (255 - a)) / 255;
// //ratio blending
B = CLIP3((b * (100 - ratio) + B * ratio) / 100, 0, 255);
G = CLIP3((g * (100 - ratio) + G * ratio) / 100, 0, 255);
R = CLIP3((r * (100 - ratio) + R * ratio) / 100, 0, 255);
srcData[pos_src] = B;
srcData[pos_src + 1] = G;
srcData[pos_src + 2] = R;
}
pMask += 3;
}
}
free(irisMask);
return ret;
};
#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
using namespace std;
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(const char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(const char * bytes_to_encode, unsigned int in_len)
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++);
if(i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
{
ret += base64_chars[char_array_4[i]];
}
i = 0;
}
}
if(i)
{
for(j = i; j < 3; j++)
{
char_array_3[j] = '\0';
}
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(j = 0; (j < i + 1); j++)
{
ret += base64_chars[char_array_4[j]];
}
while((i++ < 3))
{
ret += '=';
}
}
return ret;
}
int main29(int argc, char* argv[]){
// std::string stEsQuery = "https://api-cn.faceplusplus.com/facepp/v3/detect";
std::string stEsQuery = "https://api-cn.faceplusplus.com/facepp/v1/face/thousandlandmark";
URI uri(stEsQuery);
const Poco::Net::Context::Ptr context(
new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "",
Poco::Net::Context::VERIFY_NONE));
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(), context);
string MEGVII_KEY = "-6zs61jR1M4GqzE9jIO3eiL1W1sojaeE";
string MEGVII_SECRET = "J82yKgSplMDppw9oPpHeTVTA4hYxp0iB";
HTTPRequest es_request(HTTPRequest::HTTP_POST,uri.getPathAndQuery(),HTTPRequest::HTTP_1_1);
es_request.setContentType("multipart/form-data");
HTMLForm form;
form.setEncoding(HTMLForm::ENCODING_MULTIPART);
form.add("api_key", MEGVII_KEY);
form.add("api_secret", MEGVII_SECRET);
// form.add("return_landmark", "2");
form.add("return_landmark", "right_eye");
// fstream f;
// f.open("/Users/edz/Downloads/tongshi.png", ios::in|ios::binary);
// f.seekg(0, std::ios_base::end); //设置偏移量至文件结尾
// std::streampos sp = f.tellg(); //获取文件大小
// int size = sp;
// char* buffer = (char*)malloc(sizeof(char)*size);
// f.seekg(0, std::ios_base::beg); //设置偏移量至文件开头
// f.read(buffer,size); //将文件内容读入buffer
// cout << "file size:" << size << endl;
// string imgBase64 = base64_encode(buffer, size); //编码
// form.add("image_base64", imgBase64);
form.addPart("image_file",new FilePartSource("/Users/edz/Downloads/meitonghei.jpeg"));
form.prepareSubmit(es_request);
form.write(session.sendRequest(es_request));
HTTPResponse es_response;
std::istream &istream = session.receiveResponse(es_response);
const HTTPResponse::HTTPStatus &status = es_response.getStatus();
if(HTTPResponse::HTTPStatus::HTTP_OK == status){
std::string stRes;
StreamCopier::copyToString(istream, stRes);
std::cout<< stRes <<std::endl;
}else{
std::string stRes;
StreamCopier::copyToString(istream, stRes);
std::cout<< stRes <<std::endl;
std::cout<< status <<std::endl;
}
}
int main28(int argc, char* argv[]){
try
{
// Load face detection and pose estimation models.
// frontal_face_detector detector = get_frontal_face_detector();
// shape_predictor pose_model;
// deserialize("/Users/edz/Downloads/shape_predictor_68_face_landmarks.dat") >> pose_model;
// Grab and process frames until the main window is closed by the user.
string photoPath = string(argv[1]);
string irisPath = string(argv[2]);
cv::Mat temp = imread(photoPath);
// cv_image<bgr_pixel> cimg(temp);
// Detect faces
// std::vector<dlib::rectangle> faces = detector(cimg);
// Find the pose of each face.
// std::vector<full_object_detection> shapes;
// for (unsigned long i = 0; i < faces.size(); ++i)
// shapes.push_back(pose_model(cimg, faces[i]));
int srcPoints[64*2];
// string pointJsonStr = "{\"request_id\":\"1617882543,a020830b-7fb2-4a6b-ad2f-46b4f85f8d1d\",\"time_used\":65,\"faces\":[{\"face_token\":\"3b4a8cf00f5ffb79d679e79760c8238a\",\"face_rectangle\":{\"top\":87,\"left\":179,\"width\":141,\"height\":141},\"landmark\":{\"contour_chin\":{\"x\":232,\"y\":227},\"contour_left1\":{\"x\":180,\"y\":107},\"contour_left10\":{\"x\":190,\"y\":184},\"contour_left11\":{\"x\":194,\"y\":192},\"contour_left12\":{\"x\":199,\"y\":199},\"contour_left13\":{\"x\":204,\"y\":206},\"contour_left14\":{\"x\":209,\"y\":213},\"contour_left15\":{\"x\":215,\"y\":219},\"contour_left16\":{\"x\":222,\"y\":224},\"contour_left2\":{\"x\":179,\"y\":116},\"contour_left3\":{\"x\":178,\"y\":125},\"contour_left4\":{\"x\":178,\"y\":133},\"contour_left5\":{\"x\":179,\"y\":142},\"contour_left6\":{\"x\":180,\"y\":151},\"contour_left7\":{\"x\":182,\"y\":159},\"contour_left8\":{\"x\":184,\"y\":168},\"contour_left9\":{\"x\":187,\"y\":176},\"contour_right1\":{\"x\":318,\"y\":103},\"contour_right10\":{\"x\":302,\"y\":194},\"contour_right11\":{\"x\":294,\"y\":202},\"contour_right12\":{\"x\":286,\"y\":209},\"contour_right13\":{\"x\":277,\"y\":215},\"contour_right14\":{\"x\":267,\"y\":220},\"contour_right15\":{\"x\":256,\"y\":225},\"contour_right16\":{\"x\":244,\"y\":227},\"contour_right2\":{\"x\":319,\"y\":113},\"contour_right3\":{\"x\":320,\"y\":124},\"contour_right4\":{\"x\":319,\"y\":134},\"contour_right5\":{\"x\":319,\"y\":144},\"contour_right6\":{\"x\":317,\"y\":155},\"contour_right7\":{\"x\":315,\"y\":165},\"contour_right8\":{\"x\":312,\"y\":175},\"contour_right9\":{\"x\":307,\"y\":185},\"left_eye_bottom\":{\"x\":198,\"y\":119},\"left_eye_center\":{\"x\":203,\"y\":114},\"left_eye_left_corner\":{\"x\":188,\"y\":115},\"left_eye_lower_left_quarter\":{\"x\":192,\"y\":118},\"left_eye_lower_right_quarter\":{\"x\":205,\"y\":119},\"left_eye_pupil\":{\"x\":203,\"y\":114},\"left_eye_right_corner\":{\"x\":212,\"y\":118},\"left_eye_top\":{\"x\":199,\"y\":109},\"left_eye_upper_left_quarter\":{\"x\":192,\"y\":110},\"left_eye_upper_right_quarter\":{\"x\":207,\"y\":111},\"left_eyebrow_left_corner\":{\"x\":178,\"y\":98},\"left_eyebrow_lower_left_quarter\":{\"x\":185,\"y\":98},\"left_eyebrow_lower_middle\":{\"x\":193,\"y\":98},\"left_eyebrow_lower_right_corner\":{\"x\":210,\"y\":102},\"left_eyebrow_lower_right_quarter\":{\"x\":202,\"y\":99},\"left_eyebrow_upper_left_quarter\":{\"x\":184,\"y\":91},\"left_eyebrow_upper_middle\":{\"x\":193,\"y\":90},\"left_eyebrow_upper_right_corner\":{\"x\":211,\"y\":97},\"left_eyebrow_upper_right_quarter\":{\"x\":203,\"y\":92},\"mouth_left_corner\":{\"x\":209,\"y\":182},\"mouth_lower_lip_bottom\":{\"x\":230,\"y\":197},\"mouth_lower_lip_left_contour1\":{\"x\":219,\"y\":186},\"mouth_lower_lip_left_contour2\":{\"x\":214,\"y\":189},\"mouth_lower_lip_left_contour3\":{\"x\":220,\"y\":195},\"mouth_lower_lip_right_contour1\":{\"x\":246,\"y\":186},\"mouth_lower_lip_right_contour2\":{\"x\":254,\"y\":189},\"mouth_lower_lip_right_contour3\":{\"x\":243,\"y\":195},\"mouth_lower_lip_top\":{\"x\":229,\"y\":187},\"mouth_right_corner\":{\"x\":263,\"y\":181},\"mouth_upper_lip_bottom\":{\"x\":229,\"y\":186},\"mouth_upper_lip_left_contour1\":{\"x\":222,\"y\":179},\"mouth_upper_lip_left_contour2\":{\"x\":215,\"y\":180},\"mouth_upper_lip_left_contour3\":{\"x\":212,\"y\":183},\"mouth_upper_lip_left_contour4\":{\"x\":219,\"y\":185},\"mouth_upper_lip_right_contour1\":{\"x\":235,\"y\":179},\"mouth_upper_lip_right_contour2\":{\"x\":249,\"y\":180},\"mouth_upper_lip_right_contour3\":{\"x\":258,\"y\":182},\"mouth_upper_lip_right_contour4\":{\"x\":245,\"y\":184},\"mouth_upper_lip_top\":{\"x\":228,\"y\":181},\"nose_bridge1\":{\"x\":225,\"y\":113},\"nose_bridge2\":{\"x\":223,\"y\":127},\"nose_bridge3\":{\"x\":220,\"y\":141},\"nose_left_contour1\":{\"x\":219,\"y\":119},\"nose_left_contour2\":{\"x\":213,\"y\":148},\"nose_left_contour3\":{\"x\":210,\"y\":160},\"nose_left_contour4\":{\"x\":213,\"y\":164},\"nose_left_contour5\":{\"x\":218,\"y\":166},\"nose_middle_contour\":{\"x\":224,\"y\":168},\"nose_right_contour1\":{\"x\":237,\"y\":117},\"nose_right_contour2\":{\"x\":241,\"y\":147},\"nose_right_contour3\":{\"x\":246,\"y\":160},\"nose_right_contour4\":{\"x\":239,\"y\":164},\"nose_right_contour5\":{\"x\":231,\"y\":166},\"nose_tip\":{\"x\":217,\"y\":156},\"right_eye_bottom\":{\"x\":262,\"y\":119},\"right_eye_center\":{\"x\":264,\"y\":112},\"right_eye_left_corner\":{\"x\":246,\"y\":118},\"right_eye_lower_left_quarter\":{\"x\":254,\"y\":119},\"right_eye_lower_right_quarter\":{\"x\":270,\"y\":117},\"right_eye_pupil\":{\"x\":264,\"y\":112},\"right_eye_right_corner\":{\"x\":277,\"y\":113},\"right_eye_top\":{\"x\":261,\"y\":107},\"right_eye_upper_left_quarter\":{\"x\":252,\"y\":111},\"right_eye_upper_right_quarter\":{\"x\":269,\"y\":109},\"right_eyebrow_lower_left_corner\":{\"x\":239,\"y\":99},\"right_eyebrow_lower_left_quarter\":{\"x\":251,\"y\":97},\"right_eyebrow_lower_middle\":{\"x\":264,\"y\":96},\"right_eyebrow_lower_right_quarter\":{\"x\":278,\"y\":97},\"right_eyebrow_right_corner\":{\"x\":292,\"y\":99},\"right_eyebrow_upper_left_corner\":{\"x\":238,\"y\":93},\"right_eyebrow_upper_left_quarter\":{\"x\":250,\"y\":90},\"right_eyebrow_upper_middle\":{\"x\":264,\"y\":89},\"right_eyebrow_upper_right_quarter\":{\"x\":279,\"y\":91}}}],\"image_id\":\"2yT1Ccz7vyIPlJqmEXE+oQ==\",\"face_num\":1}";
string pointJsonStr = "{\"time_used\": 134, \"request_id\": \"1617937070,e4fb445c-50af-4a8c-be39-14c58e946507\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 113, \"x\": 262}, \"right_eye_38\": {\"y\": 119, \"x\": 253}, \"right_eye_39\": {\"y\": 119, \"x\": 254}, \"right_eye_36\": {\"y\": 118, \"x\": 252}, \"right_eye_37\": {\"y\": 118, \"x\": 253}, \"right_eye_34\": {\"y\": 118, \"x\": 250}, \"right_eye_35\": {\"y\": 118, \"x\": 251}, \"right_eye_32\": {\"y\": 117, \"x\": 249}, \"right_eye_33\": {\"y\": 117, \"x\": 249}, \"right_eye_30\": {\"y\": 115, \"x\": 249}, \"right_eye_31\": {\"y\": 116, \"x\": 249}, \"right_eye_10\": {\"y\": 108, \"x\": 266}, \"right_eye_11\": {\"y\": 108, \"x\": 265}, \"right_eye_12\": {\"y\": 108, \"x\": 264}, \"right_eye_13\": {\"y\": 108, \"x\": 263}, \"right_eye_14\": {\"y\": 108, \"x\": 262}, \"right_eye_15\": {\"y\": 108, \"x\": 261}, \"right_eye_16\": {\"y\": 108, \"x\": 260}, \"right_eye_17\": {\"y\": 108, \"x\": 259}, \"right_eye_18\": {\"y\": 109, \"x\": 258}, \"right_eye_19\": {\"y\": 109, \"x\": 257}, \"right_eye_56\": {\"y\": 117, \"x\": 269}, \"right_eye_57\": {\"y\": 116, \"x\": 270}, \"right_eye_50\": {\"y\": 118, \"x\": 264}, \"right_eye_51\": {\"y\": 118, \"x\": 265}, \"right_eye_52\": {\"y\": 118, \"x\": 266}, \"right_eye_53\": {\"y\": 118, \"x\": 266}, \"right_eye_pupil_radius\": 6, \"right_eye_8\": {\"y\": 109, \"x\": 267}, \"right_eye_9\": {\"y\": 109, \"x\": 266}, \"right_eye_6\": {\"y\": 109, \"x\": 269}, \"right_eye_7\": {\"y\": 109, \"x\": 268}, \"right_eye_4\": {\"y\": 110, \"x\": 271}, \"right_eye_5\": {\"y\": 110, \"x\": 270}, \"right_eye_2\": {\"y\": 111, \"x\": 272}, \"right_eye_3\": {\"y\": 111, \"x\": 272}, \"right_eye_0\": {\"y\": 113, \"x\": 273}, \"right_eye_1\": {\"y\": 112, \"x\": 273}, \"right_eye_58\": {\"y\": 116, \"x\": 270}, \"right_eye_29\": {\"y\": 114, \"x\": 249}, \"right_eye_28\": {\"y\": 113, \"x\": 250}, \"right_eye_62\": {\"y\": 114, \"x\": 273}, \"right_eye_21\": {\"y\": 109, \"x\": 255}, \"right_eye_20\": {\"y\": 109, \"x\": 256}, \"right_eye_23\": {\"y\": 110, \"x\": 254}, \"right_eye_22\": {\"y\": 110, \"x\": 254}, \"right_eye_25\": {\"y\": 111, \"x\": 252}, \"right_eye_24\": {\"y\": 111, \"x\": 253}, \"right_eye_27\": {\"y\": 112, \"x\": 251}, \"right_eye_26\": {\"y\": 112, \"x\": 251}, \"right_eye_59\": {\"y\": 116, \"x\": 271}, \"right_eye_61\": {\"y\": 115, \"x\": 272}, \"right_eye_60\": {\"y\": 115, \"x\": 272}, \"right_eye_49\": {\"y\": 119, \"x\": 263}, \"right_eye_48\": {\"y\": 119, \"x\": 262}, \"right_eye_47\": {\"y\": 119, \"x\": 261}, \"right_eye_46\": {\"y\": 119, \"x\": 260}, \"right_eye_45\": {\"y\": 119, \"x\": 259}, \"right_eye_44\": {\"y\": 119, \"x\": 259}, \"right_eye_43\": {\"y\": 119, \"x\": 258}, \"right_eye_42\": {\"y\": 119, \"x\": 257}, \"right_eye_41\": {\"y\": 119, \"x\": 256}, \"right_eye_40\": {\"y\": 119, \"x\": 255}, \"right_eye_54\": {\"y\": 117, \"x\": 267}, \"right_eye_55\": {\"y\": 117, \"x\": 268}}}, \"face_rectangle\": {\"width\": 143, \"top\": 86, \"height\": 143, \"left\": 177}}}";
Poco::JSON::Parser parser;
const Dynamic::Var &var = parser.parse(pointJsonStr);
int right_eye_pupil_radius;
if(!var.isEmpty()){
const JSON::Object::Ptr &objPtr = var.extract<Poco::JSON::Object::Ptr>();
// const JSON::Array::Ptr &facesArrayPtr = objPtr->getArray("faces");
//1000关键点
const JSON::Object::Ptr &facesArrayPtr = objPtr->getObject("face");
// const SharedPtr<Poco::JSON::Object> &faceItem0 = facesArrayPtr->getObject(0);
JSON::Object::Ptr pointPtr = facesArrayPtr->getObject("landmark");
int x,y;
JSON::Object::Ptr point;
string direct;
direct = "right";
std::vector<string> rightPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
direct = "left";
std::vector<string> leftPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
// for(int i=0,index=0;i<rightPoints.size();++i){
// point = pointPtr->getObject(rightPoints.at(i));
// x = point->get("x");
// y = point->get("y");
//// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
//// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
// srcPoints[index++] = x;
// srcPoints[index++] = y;
// }
//1000点
pointPtr = pointPtr->getObject("right_eye");
const JSON::Object::NameList &names = pointPtr->getNames();
cout << names.size() << endl;
int right_eye_pupil_center_x;
int right_eye_pupil_center_y;
for(int i=0,index=0;i<names.size();++i){
string key = names.at(i);
if("right_eye_pupil_radius"==key){
right_eye_pupil_radius = pointPtr->get(key);
continue;
}
point = pointPtr->getObject(key);
if("right_eye_pupil_center"==key){
right_eye_pupil_center_x = point->get("x");
right_eye_pupil_center_y = point->get("y");
srcPoints[2*63] = right_eye_pupil_center_x;
srcPoints[2*63+1] = right_eye_pupil_center_y;
continue;
}
x = point->get("x");
y = point->get("y");
// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
srcPoints[index++] = x;
srcPoints[index++] = y;
}
// circle(temp, cvPoint(right_eye_pupil_center_x, right_eye_pupil_center_y), right_eye_pupil_radius, cv::Scalar(0, 255, 0), 1);
cout << "right_eye_pupil_radius=" << right_eye_pupil_radius << endl;
}
// if (!shapes.empty()) {
// for (int i = 0,index = 0; i < 68; i++) {
// if(i>=36&&i<=41){
// cout << "编号"<< i << "," << "x=" << shapes[0].part(i).x() << ",y=" << shapes[0].part(i).y() << endl;
// circle(temp, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 3, cv::Scalar(0, 0, 255), -1);
// srcPoints[index++] = shapes[0].part(i).x();
// srcPoints[index++] = shapes[0].part(i).y();
// }
// }
// int cenx = (srcPoints[2 * 0] + srcPoints[2 * 3])/2;
// int ceny = (srcPoints[2 * 0 + 1] + srcPoints[2 * 3 + 1])/2;
// circle(temp, cvPoint(cenx, ceny), 3, cv::Scalar(0, 0, 255), -1);
// }
//Display it all on the screen
// imshow("Dlib特征点", temp);
// waitKey(0);
//美瞳
cv::Mat meitong = imread(irisPath);
unsigned char* maskData = meitong.data;
int mWidth = meitong.cols, mHeight = meitong.rows, mStride = mWidth * meitong.channels();
unsigned char* srcData = temp.data;
int width = temp.cols, height = temp.rows, stride = width * temp.channels();
// f_BeautyIris(srcData,width,height,stride,srcPoints,maskData,mWidth,mHeight,mStride,NULL,100,right_eye_pupil_radius);
imshow("美瞳", temp);
waitKey(0);
}
catch (serialization_error& e)
{
cout << "You need dlib's default face landmarking model file to run this example." << endl;
cout << "You can get it from the following URL: " << endl;
cout << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
cout << endl << e.what() << endl;
}
catch (exception& e)
{
cout << e.what() << endl;
}
// Mat face = imread("/Users/edz/Downloads/tongshi.png");
// imshow("face",face);
// waitKey(0);
// cout << "aaa" << endl;
}
int main30(int argc, char* argv[]){
try
{
// Load face detection and pose estimation models.
frontal_face_detector detector = get_frontal_face_detector();
shape_predictor pose_model;
deserialize("/Users/edz/Downloads/shape_predictor_68_face_landmarks.dat") >> pose_model;
// Grab and process frames until the main window is closed by the user.
string photoPath = string(argv[1]);
string irisPath = string(argv[2]);
cv::Mat temp = imread(photoPath);
cv_image<bgr_pixel> cimg(temp);
// Detect faces
std::vector<dlib::rectangle> faces = detector(cimg);
// Find the pose of each face.
std::vector<full_object_detection> shapes;
for (unsigned long i = 0; i < faces.size(); ++i)
shapes.push_back(pose_model(cimg, faces[i]));
int srcPoints[6*2];
// string pointJsonStr = "{\"request_id\":\"1617882543,a020830b-7fb2-4a6b-ad2f-46b4f85f8d1d\",\"time_used\":65,\"faces\":[{\"face_token\":\"3b4a8cf00f5ffb79d679e79760c8238a\",\"face_rectangle\":{\"top\":87,\"left\":179,\"width\":141,\"height\":141},\"landmark\":{\"contour_chin\":{\"x\":232,\"y\":227},\"contour_left1\":{\"x\":180,\"y\":107},\"contour_left10\":{\"x\":190,\"y\":184},\"contour_left11\":{\"x\":194,\"y\":192},\"contour_left12\":{\"x\":199,\"y\":199},\"contour_left13\":{\"x\":204,\"y\":206},\"contour_left14\":{\"x\":209,\"y\":213},\"contour_left15\":{\"x\":215,\"y\":219},\"contour_left16\":{\"x\":222,\"y\":224},\"contour_left2\":{\"x\":179,\"y\":116},\"contour_left3\":{\"x\":178,\"y\":125},\"contour_left4\":{\"x\":178,\"y\":133},\"contour_left5\":{\"x\":179,\"y\":142},\"contour_left6\":{\"x\":180,\"y\":151},\"contour_left7\":{\"x\":182,\"y\":159},\"contour_left8\":{\"x\":184,\"y\":168},\"contour_left9\":{\"x\":187,\"y\":176},\"contour_right1\":{\"x\":318,\"y\":103},\"contour_right10\":{\"x\":302,\"y\":194},\"contour_right11\":{\"x\":294,\"y\":202},\"contour_right12\":{\"x\":286,\"y\":209},\"contour_right13\":{\"x\":277,\"y\":215},\"contour_right14\":{\"x\":267,\"y\":220},\"contour_right15\":{\"x\":256,\"y\":225},\"contour_right16\":{\"x\":244,\"y\":227},\"contour_right2\":{\"x\":319,\"y\":113},\"contour_right3\":{\"x\":320,\"y\":124},\"contour_right4\":{\"x\":319,\"y\":134},\"contour_right5\":{\"x\":319,\"y\":144},\"contour_right6\":{\"x\":317,\"y\":155},\"contour_right7\":{\"x\":315,\"y\":165},\"contour_right8\":{\"x\":312,\"y\":175},\"contour_right9\":{\"x\":307,\"y\":185},\"left_eye_bottom\":{\"x\":198,\"y\":119},\"left_eye_center\":{\"x\":203,\"y\":114},\"left_eye_left_corner\":{\"x\":188,\"y\":115},\"left_eye_lower_left_quarter\":{\"x\":192,\"y\":118},\"left_eye_lower_right_quarter\":{\"x\":205,\"y\":119},\"left_eye_pupil\":{\"x\":203,\"y\":114},\"left_eye_right_corner\":{\"x\":212,\"y\":118},\"left_eye_top\":{\"x\":199,\"y\":109},\"left_eye_upper_left_quarter\":{\"x\":192,\"y\":110},\"left_eye_upper_right_quarter\":{\"x\":207,\"y\":111},\"left_eyebrow_left_corner\":{\"x\":178,\"y\":98},\"left_eyebrow_lower_left_quarter\":{\"x\":185,\"y\":98},\"left_eyebrow_lower_middle\":{\"x\":193,\"y\":98},\"left_eyebrow_lower_right_corner\":{\"x\":210,\"y\":102},\"left_eyebrow_lower_right_quarter\":{\"x\":202,\"y\":99},\"left_eyebrow_upper_left_quarter\":{\"x\":184,\"y\":91},\"left_eyebrow_upper_middle\":{\"x\":193,\"y\":90},\"left_eyebrow_upper_right_corner\":{\"x\":211,\"y\":97},\"left_eyebrow_upper_right_quarter\":{\"x\":203,\"y\":92},\"mouth_left_corner\":{\"x\":209,\"y\":182},\"mouth_lower_lip_bottom\":{\"x\":230,\"y\":197},\"mouth_lower_lip_left_contour1\":{\"x\":219,\"y\":186},\"mouth_lower_lip_left_contour2\":{\"x\":214,\"y\":189},\"mouth_lower_lip_left_contour3\":{\"x\":220,\"y\":195},\"mouth_lower_lip_right_contour1\":{\"x\":246,\"y\":186},\"mouth_lower_lip_right_contour2\":{\"x\":254,\"y\":189},\"mouth_lower_lip_right_contour3\":{\"x\":243,\"y\":195},\"mouth_lower_lip_top\":{\"x\":229,\"y\":187},\"mouth_right_corner\":{\"x\":263,\"y\":181},\"mouth_upper_lip_bottom\":{\"x\":229,\"y\":186},\"mouth_upper_lip_left_contour1\":{\"x\":222,\"y\":179},\"mouth_upper_lip_left_contour2\":{\"x\":215,\"y\":180},\"mouth_upper_lip_left_contour3\":{\"x\":212,\"y\":183},\"mouth_upper_lip_left_contour4\":{\"x\":219,\"y\":185},\"mouth_upper_lip_right_contour1\":{\"x\":235,\"y\":179},\"mouth_upper_lip_right_contour2\":{\"x\":249,\"y\":180},\"mouth_upper_lip_right_contour3\":{\"x\":258,\"y\":182},\"mouth_upper_lip_right_contour4\":{\"x\":245,\"y\":184},\"mouth_upper_lip_top\":{\"x\":228,\"y\":181},\"nose_bridge1\":{\"x\":225,\"y\":113},\"nose_bridge2\":{\"x\":223,\"y\":127},\"nose_bridge3\":{\"x\":220,\"y\":141},\"nose_left_contour1\":{\"x\":219,\"y\":119},\"nose_left_contour2\":{\"x\":213,\"y\":148},\"nose_left_contour3\":{\"x\":210,\"y\":160},\"nose_left_contour4\":{\"x\":213,\"y\":164},\"nose_left_contour5\":{\"x\":218,\"y\":166},\"nose_middle_contour\":{\"x\":224,\"y\":168},\"nose_right_contour1\":{\"x\":237,\"y\":117},\"nose_right_contour2\":{\"x\":241,\"y\":147},\"nose_right_contour3\":{\"x\":246,\"y\":160},\"nose_right_contour4\":{\"x\":239,\"y\":164},\"nose_right_contour5\":{\"x\":231,\"y\":166},\"nose_tip\":{\"x\":217,\"y\":156},\"right_eye_bottom\":{\"x\":262,\"y\":119},\"right_eye_center\":{\"x\":264,\"y\":112},\"right_eye_left_corner\":{\"x\":246,\"y\":118},\"right_eye_lower_left_quarter\":{\"x\":254,\"y\":119},\"right_eye_lower_right_quarter\":{\"x\":270,\"y\":117},\"right_eye_pupil\":{\"x\":264,\"y\":112},\"right_eye_right_corner\":{\"x\":277,\"y\":113},\"right_eye_top\":{\"x\":261,\"y\":107},\"right_eye_upper_left_quarter\":{\"x\":252,\"y\":111},\"right_eye_upper_right_quarter\":{\"x\":269,\"y\":109},\"right_eyebrow_lower_left_corner\":{\"x\":239,\"y\":99},\"right_eyebrow_lower_left_quarter\":{\"x\":251,\"y\":97},\"right_eyebrow_lower_middle\":{\"x\":264,\"y\":96},\"right_eyebrow_lower_right_quarter\":{\"x\":278,\"y\":97},\"right_eyebrow_right_corner\":{\"x\":292,\"y\":99},\"right_eyebrow_upper_left_corner\":{\"x\":238,\"y\":93},\"right_eyebrow_upper_left_quarter\":{\"x\":250,\"y\":90},\"right_eyebrow_upper_middle\":{\"x\":264,\"y\":89},\"right_eyebrow_upper_right_quarter\":{\"x\":279,\"y\":91}}}],\"image_id\":\"2yT1Ccz7vyIPlJqmEXE+oQ==\",\"face_num\":1}";
// string pointJsonStr = "{\"time_used\": 134, \"request_id\": \"1617937070,e4fb445c-50af-4a8c-be39-14c58e946507\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 113, \"x\": 262}, \"right_eye_38\": {\"y\": 119, \"x\": 253}, \"right_eye_39\": {\"y\": 119, \"x\": 254}, \"right_eye_36\": {\"y\": 118, \"x\": 252}, \"right_eye_37\": {\"y\": 118, \"x\": 253}, \"right_eye_34\": {\"y\": 118, \"x\": 250}, \"right_eye_35\": {\"y\": 118, \"x\": 251}, \"right_eye_32\": {\"y\": 117, \"x\": 249}, \"right_eye_33\": {\"y\": 117, \"x\": 249}, \"right_eye_30\": {\"y\": 115, \"x\": 249}, \"right_eye_31\": {\"y\": 116, \"x\": 249}, \"right_eye_10\": {\"y\": 108, \"x\": 266}, \"right_eye_11\": {\"y\": 108, \"x\": 265}, \"right_eye_12\": {\"y\": 108, \"x\": 264}, \"right_eye_13\": {\"y\": 108, \"x\": 263}, \"right_eye_14\": {\"y\": 108, \"x\": 262}, \"right_eye_15\": {\"y\": 108, \"x\": 261}, \"right_eye_16\": {\"y\": 108, \"x\": 260}, \"right_eye_17\": {\"y\": 108, \"x\": 259}, \"right_eye_18\": {\"y\": 109, \"x\": 258}, \"right_eye_19\": {\"y\": 109, \"x\": 257}, \"right_eye_56\": {\"y\": 117, \"x\": 269}, \"right_eye_57\": {\"y\": 116, \"x\": 270}, \"right_eye_50\": {\"y\": 118, \"x\": 264}, \"right_eye_51\": {\"y\": 118, \"x\": 265}, \"right_eye_52\": {\"y\": 118, \"x\": 266}, \"right_eye_53\": {\"y\": 118, \"x\": 266}, \"right_eye_pupil_radius\": 6, \"right_eye_8\": {\"y\": 109, \"x\": 267}, \"right_eye_9\": {\"y\": 109, \"x\": 266}, \"right_eye_6\": {\"y\": 109, \"x\": 269}, \"right_eye_7\": {\"y\": 109, \"x\": 268}, \"right_eye_4\": {\"y\": 110, \"x\": 271}, \"right_eye_5\": {\"y\": 110, \"x\": 270}, \"right_eye_2\": {\"y\": 111, \"x\": 272}, \"right_eye_3\": {\"y\": 111, \"x\": 272}, \"right_eye_0\": {\"y\": 113, \"x\": 273}, \"right_eye_1\": {\"y\": 112, \"x\": 273}, \"right_eye_58\": {\"y\": 116, \"x\": 270}, \"right_eye_29\": {\"y\": 114, \"x\": 249}, \"right_eye_28\": {\"y\": 113, \"x\": 250}, \"right_eye_62\": {\"y\": 114, \"x\": 273}, \"right_eye_21\": {\"y\": 109, \"x\": 255}, \"right_eye_20\": {\"y\": 109, \"x\": 256}, \"right_eye_23\": {\"y\": 110, \"x\": 254}, \"right_eye_22\": {\"y\": 110, \"x\": 254}, \"right_eye_25\": {\"y\": 111, \"x\": 252}, \"right_eye_24\": {\"y\": 111, \"x\": 253}, \"right_eye_27\": {\"y\": 112, \"x\": 251}, \"right_eye_26\": {\"y\": 112, \"x\": 251}, \"right_eye_59\": {\"y\": 116, \"x\": 271}, \"right_eye_61\": {\"y\": 115, \"x\": 272}, \"right_eye_60\": {\"y\": 115, \"x\": 272}, \"right_eye_49\": {\"y\": 119, \"x\": 263}, \"right_eye_48\": {\"y\": 119, \"x\": 262}, \"right_eye_47\": {\"y\": 119, \"x\": 261}, \"right_eye_46\": {\"y\": 119, \"x\": 260}, \"right_eye_45\": {\"y\": 119, \"x\": 259}, \"right_eye_44\": {\"y\": 119, \"x\": 259}, \"right_eye_43\": {\"y\": 119, \"x\": 258}, \"right_eye_42\": {\"y\": 119, \"x\": 257}, \"right_eye_41\": {\"y\": 119, \"x\": 256}, \"right_eye_40\": {\"y\": 119, \"x\": 255}, \"right_eye_54\": {\"y\": 117, \"x\": 267}, \"right_eye_55\": {\"y\": 117, \"x\": 268}}}, \"face_rectangle\": {\"width\": 143, \"top\": 86, \"height\": 143, \"left\": 177}}}";
string pointJsonStr = "{\"time_used\": 163, \"request_id\": \"1617953825,2bfa2aa7-07df-4bec-bbc2-712b04fd1aae\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 162, \"x\": 476}, \"right_eye_38\": {\"y\": 178, \"x\": 449}, \"right_eye_39\": {\"y\": 179, \"x\": 452}, \"right_eye_36\": {\"y\": 176, \"x\": 444}, \"right_eye_37\": {\"y\": 177, \"x\": 446}, \"right_eye_34\": {\"y\": 174, \"x\": 439}, \"right_eye_35\": {\"y\": 175, \"x\": 441}, \"right_eye_32\": {\"y\": 170, \"x\": 435}, \"right_eye_33\": {\"y\": 172, \"x\": 437}, \"right_eye_30\": {\"y\": 164, \"x\": 437}, \"right_eye_31\": {\"y\": 167, \"x\": 436}, \"right_eye_10\": {\"y\": 154, \"x\": 494}, \"right_eye_11\": {\"y\": 153, \"x\": 491}, \"right_eye_12\": {\"y\": 153, \"x\": 488}, \"right_eye_13\": {\"y\": 152, \"x\": 485}, \"right_eye_14\": {\"y\": 151, \"x\": 482}, \"right_eye_15\": {\"y\": 151, \"x\": 479}, \"right_eye_16\": {\"y\": 151, \"x\": 476}, \"right_eye_17\": {\"y\": 151, \"x\": 473}, \"right_eye_18\": {\"y\": 151, \"x\": 470}, \"right_eye_19\": {\"y\": 151, \"x\": 467}, \"right_eye_56\": {\"y\": 184, \"x\": 499}, \"right_eye_57\": {\"y\": 183, \"x\": 502}, \"right_eye_50\": {\"y\": 185, \"x\": 482}, \"right_eye_51\": {\"y\": 185, \"x\": 485}, \"right_eye_52\": {\"y\": 185, \"x\": 488}, \"right_eye_53\": {\"y\": 185, \"x\": 491}, \"right_eye_pupil_radius\": 21, \"right_eye_8\": {\"y\": 157, \"x\": 499}, \"right_eye_9\": {\"y\": 155, \"x\": 497}, \"right_eye_6\": {\"y\": 160, \"x\": 505}, \"right_eye_7\": {\"y\": 158, \"x\": 502}, \"right_eye_4\": {\"y\": 163, \"x\": 510}, \"right_eye_5\": {\"y\": 161, \"x\": 507}, \"right_eye_2\": {\"y\": 168, \"x\": 514}, \"right_eye_3\": {\"y\": 165, \"x\": 512}, \"right_eye_0\": {\"y\": 173, \"x\": 515}, \"right_eye_1\": {\"y\": 171, \"x\": 515}, \"right_eye_58\": {\"y\": 182, \"x\": 505}, \"right_eye_29\": {\"y\": 162, \"x\": 439}, \"right_eye_28\": {\"y\": 160, \"x\": 441}, \"right_eye_62\": {\"y\": 176, \"x\": 514}, \"right_eye_21\": {\"y\": 152, \"x\": 461}, \"right_eye_20\": {\"y\": 151, \"x\": 464}, \"right_eye_23\": {\"y\": 154, \"x\": 455}, \"right_eye_22\": {\"y\": 153, \"x\": 458}, \"right_eye_25\": {\"y\": 156, \"x\": 449}, \"right_eye_24\": {\"y\": 155, \"x\": 452}, \"right_eye_27\": {\"y\": 159, \"x\": 444}, \"right_eye_26\": {\"y\": 157, \"x\": 447}, \"right_eye_59\": {\"y\": 181, \"x\": 507}, \"right_eye_61\": {\"y\": 178, \"x\": 512}, \"right_eye_60\": {\"y\": 179, \"x\": 510}, \"right_eye_49\": {\"y\": 185, \"x\": 479}, \"right_eye_48\": {\"y\": 185, \"x\": 477}, \"right_eye_47\": {\"y\": 184, \"x\": 474}, \"right_eye_46\": {\"y\": 184, \"x\": 471}, \"right_eye_45\": {\"y\": 183, \"x\": 468}, \"right_eye_44\": {\"y\": 183, \"x\": 465}, \"right_eye_43\": {\"y\": 182, \"x\": 463}, \"right_eye_42\": {\"y\": 181, \"x\": 460}, \"right_eye_41\": {\"y\": 180, \"x\": 457}, \"right_eye_40\": {\"y\": 180, \"x\": 454}, \"right_eye_54\": {\"y\": 185, \"x\": 494}, \"right_eye_55\": {\"y\": 184, \"x\": 496}}}, \"face_rectangle\": {\"width\": 464, \"top\": 59, \"height\": 464, \"left\": 147}}}";
Poco::JSON::Parser parser;
const Dynamic::Var &var = parser.parse(pointJsonStr);
int right_eye_pupil_radius;
int right_eye_pupil_center_x;
int right_eye_pupil_center_y;
if(!var.isEmpty()){
const JSON::Object::Ptr &objPtr = var.extract<Poco::JSON::Object::Ptr>();
// const JSON::Array::Ptr &facesArrayPtr = objPtr->getArray("faces");
//1000关键点
const JSON::Object::Ptr &facesArrayPtr = objPtr->getObject("face");
// const SharedPtr<Poco::JSON::Object> &faceItem0 = facesArrayPtr->getObject(0);
JSON::Object::Ptr pointPtr = facesArrayPtr->getObject("landmark");
int x,y;
JSON::Object::Ptr point;
string direct;
direct = "right";
std::vector<string> rightPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
direct = "left";
std::vector<string> leftPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
// for(int i=0,index=0;i<rightPoints.size();++i){
// point = pointPtr->getObject(rightPoints.at(i));
// x = point->get("x");
// y = point->get("y");
//// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
//// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
// srcPoints[index++] = x;
// srcPoints[index++] = y;
// }
//1000点
pointPtr = pointPtr->getObject("right_eye");
const JSON::Object::NameList &names = pointPtr->getNames();
cout << names.size() << endl;
for(int i=0,index=0;i<names.size();++i){
string key = names.at(i);
if("right_eye_pupil_radius"==key){
right_eye_pupil_radius = pointPtr->get(key);
continue;
}
point = pointPtr->getObject(key);
if("right_eye_pupil_center"==key){
right_eye_pupil_center_x = point->get("x");
right_eye_pupil_center_y = point->get("y");
// srcPoints[2*63] = right_eye_pupil_center_x;
// srcPoints[2*63+1] = right_eye_pupil_center_y;
continue;
}
// x = point->get("x");
// y = point->get("y");
// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
// srcPoints[index++] = x;
// srcPoints[index++] = y;
}
// circle(temp, cvPoint(right_eye_pupil_center_x, right_eye_pupil_center_y), right_eye_pupil_radius, cv::Scalar(0, 255, 0), 1);
cout << "right_eye_pupil_radius=" << right_eye_pupil_radius << endl;
}
if (!shapes.empty()) {
for (int i = 0,index = 0; i < 68; i++) {
if(i>=42&&i<=47){
cout << "编号"<< i << "," << "x=" << shapes[0].part(i).x() << ",y=" << shapes[0].part(i).y() << endl;
// circle(temp, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 1, cv::Scalar(0, 0, 255), -1);
srcPoints[index++] = shapes[0].part(i).x();
srcPoints[index++] = shapes[0].part(i).y();
}
}
// int cenx = (srcPoints[2 * 0] + srcPoints[2 * 3])/2;
// int ceny = (srcPoints[2 * 0 + 1] + srcPoints[2 * 3 + 1])/2;
// circle(temp, cvPoint(right_eye_pupil_center_x, right_eye_pupil_center_y), 1, cv::Scalar(0, 0, 255), -1);
}
//Display it all on the screen
// imshow("Dlib特征点", temp);
// waitKey(0);
//美瞳
cv::Mat meitong = imread(irisPath);
unsigned char* maskData = meitong.data;
int mWidth = meitong.cols, mHeight = meitong.rows, mStride = mWidth * meitong.channels();
unsigned char* srcData = temp.data;
int width = temp.cols, height = temp.rows, stride = width * temp.channels();
f_BeautyIris(srcData,width,height,stride,srcPoints,maskData,mWidth,mHeight,mStride,NULL,100,right_eye_pupil_radius,right_eye_pupil_center_x,right_eye_pupil_center_y);
imshow("美瞳", temp);
waitKey(0);
}
catch (serialization_error& e)
{
cout << "You need dlib's default face landmarking model file to run this example." << endl;
cout << "You can get it from the following URL: " << endl;
cout << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
cout << endl << e.what() << endl;
}
catch (exception& e)
{
cout << e.what() << endl;
}
// Mat face = imread("/Users/edz/Downloads/tongshi.png");
// imshow("face",face);
// waitKey(0);
// cout << "aaa" << endl;
}
int main(int argc, char* argv[]){
try
{
// Load face detection and pose estimation models.
// frontal_face_detector detector = get_frontal_face_detector();
// shape_predictor pose_model;
// deserialize("/Users/edz/Downloads/shape_predictor_68_face_landmarks.dat") >> pose_model;
// Grab and process frames until the main window is closed by the user.
string photoPath = string(argv[1]);
string irisPath = string(argv[2]);
cv::Mat temp = imread(photoPath);
// cv_image<bgr_pixel> cimg(temp);
// Detect faces
// std::vector<dlib::rectangle> faces = detector(cimg);
// Find the pose of each face.
// std::vector<full_object_detection> shapes;
// for (unsigned long i = 0; i < faces.size(); ++i)
// shapes.push_back(pose_model(cimg, faces[i]));
int srcPoints[63*2];
// string pointJsonStr = "{\"request_id\":\"1617882543,a020830b-7fb2-4a6b-ad2f-46b4f85f8d1d\",\"time_used\":65,\"faces\":[{\"face_token\":\"3b4a8cf00f5ffb79d679e79760c8238a\",\"face_rectangle\":{\"top\":87,\"left\":179,\"width\":141,\"height\":141},\"landmark\":{\"contour_chin\":{\"x\":232,\"y\":227},\"contour_left1\":{\"x\":180,\"y\":107},\"contour_left10\":{\"x\":190,\"y\":184},\"contour_left11\":{\"x\":194,\"y\":192},\"contour_left12\":{\"x\":199,\"y\":199},\"contour_left13\":{\"x\":204,\"y\":206},\"contour_left14\":{\"x\":209,\"y\":213},\"contour_left15\":{\"x\":215,\"y\":219},\"contour_left16\":{\"x\":222,\"y\":224},\"contour_left2\":{\"x\":179,\"y\":116},\"contour_left3\":{\"x\":178,\"y\":125},\"contour_left4\":{\"x\":178,\"y\":133},\"contour_left5\":{\"x\":179,\"y\":142},\"contour_left6\":{\"x\":180,\"y\":151},\"contour_left7\":{\"x\":182,\"y\":159},\"contour_left8\":{\"x\":184,\"y\":168},\"contour_left9\":{\"x\":187,\"y\":176},\"contour_right1\":{\"x\":318,\"y\":103},\"contour_right10\":{\"x\":302,\"y\":194},\"contour_right11\":{\"x\":294,\"y\":202},\"contour_right12\":{\"x\":286,\"y\":209},\"contour_right13\":{\"x\":277,\"y\":215},\"contour_right14\":{\"x\":267,\"y\":220},\"contour_right15\":{\"x\":256,\"y\":225},\"contour_right16\":{\"x\":244,\"y\":227},\"contour_right2\":{\"x\":319,\"y\":113},\"contour_right3\":{\"x\":320,\"y\":124},\"contour_right4\":{\"x\":319,\"y\":134},\"contour_right5\":{\"x\":319,\"y\":144},\"contour_right6\":{\"x\":317,\"y\":155},\"contour_right7\":{\"x\":315,\"y\":165},\"contour_right8\":{\"x\":312,\"y\":175},\"contour_right9\":{\"x\":307,\"y\":185},\"left_eye_bottom\":{\"x\":198,\"y\":119},\"left_eye_center\":{\"x\":203,\"y\":114},\"left_eye_left_corner\":{\"x\":188,\"y\":115},\"left_eye_lower_left_quarter\":{\"x\":192,\"y\":118},\"left_eye_lower_right_quarter\":{\"x\":205,\"y\":119},\"left_eye_pupil\":{\"x\":203,\"y\":114},\"left_eye_right_corner\":{\"x\":212,\"y\":118},\"left_eye_top\":{\"x\":199,\"y\":109},\"left_eye_upper_left_quarter\":{\"x\":192,\"y\":110},\"left_eye_upper_right_quarter\":{\"x\":207,\"y\":111},\"left_eyebrow_left_corner\":{\"x\":178,\"y\":98},\"left_eyebrow_lower_left_quarter\":{\"x\":185,\"y\":98},\"left_eyebrow_lower_middle\":{\"x\":193,\"y\":98},\"left_eyebrow_lower_right_corner\":{\"x\":210,\"y\":102},\"left_eyebrow_lower_right_quarter\":{\"x\":202,\"y\":99},\"left_eyebrow_upper_left_quarter\":{\"x\":184,\"y\":91},\"left_eyebrow_upper_middle\":{\"x\":193,\"y\":90},\"left_eyebrow_upper_right_corner\":{\"x\":211,\"y\":97},\"left_eyebrow_upper_right_quarter\":{\"x\":203,\"y\":92},\"mouth_left_corner\":{\"x\":209,\"y\":182},\"mouth_lower_lip_bottom\":{\"x\":230,\"y\":197},\"mouth_lower_lip_left_contour1\":{\"x\":219,\"y\":186},\"mouth_lower_lip_left_contour2\":{\"x\":214,\"y\":189},\"mouth_lower_lip_left_contour3\":{\"x\":220,\"y\":195},\"mouth_lower_lip_right_contour1\":{\"x\":246,\"y\":186},\"mouth_lower_lip_right_contour2\":{\"x\":254,\"y\":189},\"mouth_lower_lip_right_contour3\":{\"x\":243,\"y\":195},\"mouth_lower_lip_top\":{\"x\":229,\"y\":187},\"mouth_right_corner\":{\"x\":263,\"y\":181},\"mouth_upper_lip_bottom\":{\"x\":229,\"y\":186},\"mouth_upper_lip_left_contour1\":{\"x\":222,\"y\":179},\"mouth_upper_lip_left_contour2\":{\"x\":215,\"y\":180},\"mouth_upper_lip_left_contour3\":{\"x\":212,\"y\":183},\"mouth_upper_lip_left_contour4\":{\"x\":219,\"y\":185},\"mouth_upper_lip_right_contour1\":{\"x\":235,\"y\":179},\"mouth_upper_lip_right_contour2\":{\"x\":249,\"y\":180},\"mouth_upper_lip_right_contour3\":{\"x\":258,\"y\":182},\"mouth_upper_lip_right_contour4\":{\"x\":245,\"y\":184},\"mouth_upper_lip_top\":{\"x\":228,\"y\":181},\"nose_bridge1\":{\"x\":225,\"y\":113},\"nose_bridge2\":{\"x\":223,\"y\":127},\"nose_bridge3\":{\"x\":220,\"y\":141},\"nose_left_contour1\":{\"x\":219,\"y\":119},\"nose_left_contour2\":{\"x\":213,\"y\":148},\"nose_left_contour3\":{\"x\":210,\"y\":160},\"nose_left_contour4\":{\"x\":213,\"y\":164},\"nose_left_contour5\":{\"x\":218,\"y\":166},\"nose_middle_contour\":{\"x\":224,\"y\":168},\"nose_right_contour1\":{\"x\":237,\"y\":117},\"nose_right_contour2\":{\"x\":241,\"y\":147},\"nose_right_contour3\":{\"x\":246,\"y\":160},\"nose_right_contour4\":{\"x\":239,\"y\":164},\"nose_right_contour5\":{\"x\":231,\"y\":166},\"nose_tip\":{\"x\":217,\"y\":156},\"right_eye_bottom\":{\"x\":262,\"y\":119},\"right_eye_center\":{\"x\":264,\"y\":112},\"right_eye_left_corner\":{\"x\":246,\"y\":118},\"right_eye_lower_left_quarter\":{\"x\":254,\"y\":119},\"right_eye_lower_right_quarter\":{\"x\":270,\"y\":117},\"right_eye_pupil\":{\"x\":264,\"y\":112},\"right_eye_right_corner\":{\"x\":277,\"y\":113},\"right_eye_top\":{\"x\":261,\"y\":107},\"right_eye_upper_left_quarter\":{\"x\":252,\"y\":111},\"right_eye_upper_right_quarter\":{\"x\":269,\"y\":109},\"right_eyebrow_lower_left_corner\":{\"x\":239,\"y\":99},\"right_eyebrow_lower_left_quarter\":{\"x\":251,\"y\":97},\"right_eyebrow_lower_middle\":{\"x\":264,\"y\":96},\"right_eyebrow_lower_right_quarter\":{\"x\":278,\"y\":97},\"right_eyebrow_right_corner\":{\"x\":292,\"y\":99},\"right_eyebrow_upper_left_corner\":{\"x\":238,\"y\":93},\"right_eyebrow_upper_left_quarter\":{\"x\":250,\"y\":90},\"right_eyebrow_upper_middle\":{\"x\":264,\"y\":89},\"right_eyebrow_upper_right_quarter\":{\"x\":279,\"y\":91}}}],\"image_id\":\"2yT1Ccz7vyIPlJqmEXE+oQ==\",\"face_num\":1}";
// string pointJsonStr = "{\"time_used\": 134, \"request_id\": \"1617937070,e4fb445c-50af-4a8c-be39-14c58e946507\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 113, \"x\": 262}, \"right_eye_38\": {\"y\": 119, \"x\": 253}, \"right_eye_39\": {\"y\": 119, \"x\": 254}, \"right_eye_36\": {\"y\": 118, \"x\": 252}, \"right_eye_37\": {\"y\": 118, \"x\": 253}, \"right_eye_34\": {\"y\": 118, \"x\": 250}, \"right_eye_35\": {\"y\": 118, \"x\": 251}, \"right_eye_32\": {\"y\": 117, \"x\": 249}, \"right_eye_33\": {\"y\": 117, \"x\": 249}, \"right_eye_30\": {\"y\": 115, \"x\": 249}, \"right_eye_31\": {\"y\": 116, \"x\": 249}, \"right_eye_10\": {\"y\": 108, \"x\": 266}, \"right_eye_11\": {\"y\": 108, \"x\": 265}, \"right_eye_12\": {\"y\": 108, \"x\": 264}, \"right_eye_13\": {\"y\": 108, \"x\": 263}, \"right_eye_14\": {\"y\": 108, \"x\": 262}, \"right_eye_15\": {\"y\": 108, \"x\": 261}, \"right_eye_16\": {\"y\": 108, \"x\": 260}, \"right_eye_17\": {\"y\": 108, \"x\": 259}, \"right_eye_18\": {\"y\": 109, \"x\": 258}, \"right_eye_19\": {\"y\": 109, \"x\": 257}, \"right_eye_56\": {\"y\": 117, \"x\": 269}, \"right_eye_57\": {\"y\": 116, \"x\": 270}, \"right_eye_50\": {\"y\": 118, \"x\": 264}, \"right_eye_51\": {\"y\": 118, \"x\": 265}, \"right_eye_52\": {\"y\": 118, \"x\": 266}, \"right_eye_53\": {\"y\": 118, \"x\": 266}, \"right_eye_pupil_radius\": 6, \"right_eye_8\": {\"y\": 109, \"x\": 267}, \"right_eye_9\": {\"y\": 109, \"x\": 266}, \"right_eye_6\": {\"y\": 109, \"x\": 269}, \"right_eye_7\": {\"y\": 109, \"x\": 268}, \"right_eye_4\": {\"y\": 110, \"x\": 271}, \"right_eye_5\": {\"y\": 110, \"x\": 270}, \"right_eye_2\": {\"y\": 111, \"x\": 272}, \"right_eye_3\": {\"y\": 111, \"x\": 272}, \"right_eye_0\": {\"y\": 113, \"x\": 273}, \"right_eye_1\": {\"y\": 112, \"x\": 273}, \"right_eye_58\": {\"y\": 116, \"x\": 270}, \"right_eye_29\": {\"y\": 114, \"x\": 249}, \"right_eye_28\": {\"y\": 113, \"x\": 250}, \"right_eye_62\": {\"y\": 114, \"x\": 273}, \"right_eye_21\": {\"y\": 109, \"x\": 255}, \"right_eye_20\": {\"y\": 109, \"x\": 256}, \"right_eye_23\": {\"y\": 110, \"x\": 254}, \"right_eye_22\": {\"y\": 110, \"x\": 254}, \"right_eye_25\": {\"y\": 111, \"x\": 252}, \"right_eye_24\": {\"y\": 111, \"x\": 253}, \"right_eye_27\": {\"y\": 112, \"x\": 251}, \"right_eye_26\": {\"y\": 112, \"x\": 251}, \"right_eye_59\": {\"y\": 116, \"x\": 271}, \"right_eye_61\": {\"y\": 115, \"x\": 272}, \"right_eye_60\": {\"y\": 115, \"x\": 272}, \"right_eye_49\": {\"y\": 119, \"x\": 263}, \"right_eye_48\": {\"y\": 119, \"x\": 262}, \"right_eye_47\": {\"y\": 119, \"x\": 261}, \"right_eye_46\": {\"y\": 119, \"x\": 260}, \"right_eye_45\": {\"y\": 119, \"x\": 259}, \"right_eye_44\": {\"y\": 119, \"x\": 259}, \"right_eye_43\": {\"y\": 119, \"x\": 258}, \"right_eye_42\": {\"y\": 119, \"x\": 257}, \"right_eye_41\": {\"y\": 119, \"x\": 256}, \"right_eye_40\": {\"y\": 119, \"x\": 255}, \"right_eye_54\": {\"y\": 117, \"x\": 267}, \"right_eye_55\": {\"y\": 117, \"x\": 268}}}, \"face_rectangle\": {\"width\": 143, \"top\": 86, \"height\": 143, \"left\": 177}}}";
string pointJsonStr = "{\"time_used\": 163, \"request_id\": \"1617953825,2bfa2aa7-07df-4bec-bbc2-712b04fd1aae\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 162, \"x\": 476}, \"right_eye_38\": {\"y\": 178, \"x\": 449}, \"right_eye_39\": {\"y\": 179, \"x\": 452}, \"right_eye_36\": {\"y\": 176, \"x\": 444}, \"right_eye_37\": {\"y\": 177, \"x\": 446}, \"right_eye_34\": {\"y\": 174, \"x\": 439}, \"right_eye_35\": {\"y\": 175, \"x\": 441}, \"right_eye_32\": {\"y\": 170, \"x\": 435}, \"right_eye_33\": {\"y\": 172, \"x\": 437}, \"right_eye_30\": {\"y\": 164, \"x\": 437}, \"right_eye_31\": {\"y\": 167, \"x\": 436}, \"right_eye_10\": {\"y\": 154, \"x\": 494}, \"right_eye_11\": {\"y\": 153, \"x\": 491}, \"right_eye_12\": {\"y\": 153, \"x\": 488}, \"right_eye_13\": {\"y\": 152, \"x\": 485}, \"right_eye_14\": {\"y\": 151, \"x\": 482}, \"right_eye_15\": {\"y\": 151, \"x\": 479}, \"right_eye_16\": {\"y\": 151, \"x\": 476}, \"right_eye_17\": {\"y\": 151, \"x\": 473}, \"right_eye_18\": {\"y\": 151, \"x\": 470}, \"right_eye_19\": {\"y\": 151, \"x\": 467}, \"right_eye_56\": {\"y\": 184, \"x\": 499}, \"right_eye_57\": {\"y\": 183, \"x\": 502}, \"right_eye_50\": {\"y\": 185, \"x\": 482}, \"right_eye_51\": {\"y\": 185, \"x\": 485}, \"right_eye_52\": {\"y\": 185, \"x\": 488}, \"right_eye_53\": {\"y\": 185, \"x\": 491}, \"right_eye_pupil_radius\": 21, \"right_eye_8\": {\"y\": 157, \"x\": 499}, \"right_eye_9\": {\"y\": 155, \"x\": 497}, \"right_eye_6\": {\"y\": 160, \"x\": 505}, \"right_eye_7\": {\"y\": 158, \"x\": 502}, \"right_eye_4\": {\"y\": 163, \"x\": 510}, \"right_eye_5\": {\"y\": 161, \"x\": 507}, \"right_eye_2\": {\"y\": 168, \"x\": 514}, \"right_eye_3\": {\"y\": 165, \"x\": 512}, \"right_eye_0\": {\"y\": 173, \"x\": 515}, \"right_eye_1\": {\"y\": 171, \"x\": 515}, \"right_eye_58\": {\"y\": 182, \"x\": 505}, \"right_eye_29\": {\"y\": 162, \"x\": 439}, \"right_eye_28\": {\"y\": 160, \"x\": 441}, \"right_eye_62\": {\"y\": 176, \"x\": 514}, \"right_eye_21\": {\"y\": 152, \"x\": 461}, \"right_eye_20\": {\"y\": 151, \"x\": 464}, \"right_eye_23\": {\"y\": 154, \"x\": 455}, \"right_eye_22\": {\"y\": 153, \"x\": 458}, \"right_eye_25\": {\"y\": 156, \"x\": 449}, \"right_eye_24\": {\"y\": 155, \"x\": 452}, \"right_eye_27\": {\"y\": 159, \"x\": 444}, \"right_eye_26\": {\"y\": 157, \"x\": 447}, \"right_eye_59\": {\"y\": 181, \"x\": 507}, \"right_eye_61\": {\"y\": 178, \"x\": 512}, \"right_eye_60\": {\"y\": 179, \"x\": 510}, \"right_eye_49\": {\"y\": 185, \"x\": 479}, \"right_eye_48\": {\"y\": 185, \"x\": 477}, \"right_eye_47\": {\"y\": 184, \"x\": 474}, \"right_eye_46\": {\"y\": 184, \"x\": 471}, \"right_eye_45\": {\"y\": 183, \"x\": 468}, \"right_eye_44\": {\"y\": 183, \"x\": 465}, \"right_eye_43\": {\"y\": 182, \"x\": 463}, \"right_eye_42\": {\"y\": 181, \"x\": 460}, \"right_eye_41\": {\"y\": 180, \"x\": 457}, \"right_eye_40\": {\"y\": 180, \"x\": 454}, \"right_eye_54\": {\"y\": 185, \"x\": 494}, \"right_eye_55\": {\"y\": 184, \"x\": 496}}}, \"face_rectangle\": {\"width\": 464, \"top\": 59, \"height\": 464, \"left\": 147}}}";
// string pointJsonStr = "{\"time_used\": 244, \"request_id\": \"1617958929,46cc922f-79e7-4fa4-9c3d-38049509d080\", \"face\": {\"landmark\": {\"right_eye\": {\"right_eye_pupil_center\": {\"y\": 567, \"x\": 588}, \"right_eye_38\": {\"y\": 591, \"x\": 552}, \"right_eye_39\": {\"y\": 592, \"x\": 555}, \"right_eye_36\": {\"y\": 589, \"x\": 544}, \"right_eye_37\": {\"y\": 590, \"x\": 548}, \"right_eye_34\": {\"y\": 586, \"x\": 537}, \"right_eye_35\": {\"y\": 587, \"x\": 541}, \"right_eye_32\": {\"y\": 580, \"x\": 533}, \"right_eye_33\": {\"y\": 584, \"x\": 534}, \"right_eye_30\": {\"y\": 573, \"x\": 534}, \"right_eye_31\": {\"y\": 576, \"x\": 533}, \"right_eye_10\": {\"y\": 557, \"x\": 611}, \"right_eye_11\": {\"y\": 556, \"x\": 607}, \"right_eye_12\": {\"y\": 555, \"x\": 603}, \"right_eye_13\": {\"y\": 554, \"x\": 599}, \"right_eye_14\": {\"y\": 554, \"x\": 595}, \"right_eye_15\": {\"y\": 554, \"x\": 591}, \"right_eye_16\": {\"y\": 553, \"x\": 587}, \"right_eye_17\": {\"y\": 553, \"x\": 583}, \"right_eye_18\": {\"y\": 554, \"x\": 579}, \"right_eye_19\": {\"y\": 554, \"x\": 574}, \"right_eye_56\": {\"y\": 595, \"x\": 620}, \"right_eye_57\": {\"y\": 594, \"x\": 624}, \"right_eye_50\": {\"y\": 598, \"x\": 597}, \"right_eye_51\": {\"y\": 598, \"x\": 601}, \"right_eye_52\": {\"y\": 597, \"x\": 605}, \"right_eye_53\": {\"y\": 597, \"x\": 609}, \"right_eye_pupil_radius\": 33, \"right_eye_8\": {\"y\": 560, \"x\": 619}, \"right_eye_9\": {\"y\": 558, \"x\": 615}, \"right_eye_6\": {\"y\": 564, \"x\": 627}, \"right_eye_7\": {\"y\": 562, \"x\": 623}, \"right_eye_4\": {\"y\": 568, \"x\": 634}, \"right_eye_5\": {\"y\": 566, \"x\": 630}, \"right_eye_2\": {\"y\": 574, \"x\": 639}, \"right_eye_3\": {\"y\": 571, \"x\": 637}, \"right_eye_0\": {\"y\": 581, \"x\": 642}, \"right_eye_1\": {\"y\": 577, \"x\": 641}, \"right_eye_58\": {\"y\": 593, \"x\": 627}, \"right_eye_29\": {\"y\": 570, \"x\": 537}, \"right_eye_28\": {\"y\": 567, \"x\": 540}, \"right_eye_62\": {\"y\": 585, \"x\": 640}, \"right_eye_21\": {\"y\": 555, \"x\": 566}, \"right_eye_20\": {\"y\": 554, \"x\": 570}, \"right_eye_23\": {\"y\": 557, \"x\": 558}, \"right_eye_22\": {\"y\": 556, \"x\": 562}, \"right_eye_25\": {\"y\": 561, \"x\": 551}, \"right_eye_24\": {\"y\": 559, \"x\": 554}, \"right_eye_27\": {\"y\": 565, \"x\": 543}, \"right_eye_26\": {\"y\": 562, \"x\": 547}, \"right_eye_59\": {\"y\": 591, \"x\": 631}, \"right_eye_61\": {\"y\": 588, \"x\": 638}, \"right_eye_60\": {\"y\": 590, \"x\": 634}, \"right_eye_49\": {\"y\": 598, \"x\": 593}, \"right_eye_48\": {\"y\": 597, \"x\": 589}, \"right_eye_47\": {\"y\": 597, \"x\": 585}, \"right_eye_46\": {\"y\": 597, \"x\": 582}, \"right_eye_45\": {\"y\": 596, \"x\": 578}, \"right_eye_44\": {\"y\": 596, \"x\": 574}, \"right_eye_43\": {\"y\": 595, \"x\": 570}, \"right_eye_42\": {\"y\": 594, \"x\": 566}, \"right_eye_41\": {\"y\": 593, \"x\": 563}, \"right_eye_40\": {\"y\": 593, \"x\": 559}, \"right_eye_54\": {\"y\": 596, \"x\": 612}, \"right_eye_55\": {\"y\": 596, \"x\": 616}}}, \"face_rectangle\": {\"width\": 629, \"top\": 432, \"height\": 629, \"left\": 126}}}";
Poco::JSON::Parser parser;
const Dynamic::Var &var = parser.parse(pointJsonStr);
int right_eye_pupil_radius;
int right_eye_pupil_center_x;
int right_eye_pupil_center_y;
if(!var.isEmpty()){
const JSON::Object::Ptr &objPtr = var.extract<Poco::JSON::Object::Ptr>();
// const JSON::Array::Ptr &facesArrayPtr = objPtr->getArray("faces");
//1000关键点
const JSON::Object::Ptr &facesArrayPtr = objPtr->getObject("face");
// const SharedPtr<Poco::JSON::Object> &faceItem0 = facesArrayPtr->getObject(0);
JSON::Object::Ptr pointPtr = facesArrayPtr->getObject("landmark");
int x,y;
JSON::Object::Ptr point;
string direct;
direct = "right";
std::vector<string> rightPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
direct = "left";
std::vector<string> leftPoints = {direct+"_eye_left_corner",direct+"_eye_upper_left_quarter",direct+"_eye_top",
direct+"_eye_upper_right_quarter",direct+"_eye_right_corner",direct+"_eye_lower_right_quarter",
direct+"_eye_bottom",direct+"_eye_lower_left_quarter",direct+"_eye_pupil"};
// for(int i=0,index=0;i<rightPoints.size();++i){
// point = pointPtr->getObject(rightPoints.at(i));
// x = point->get("x");
// y = point->get("y");
//// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
//// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
// srcPoints[index++] = x;
// srcPoints[index++] = y;
// }
//1000点
pointPtr = pointPtr->getObject("right_eye");
const JSON::Object::NameList &names = pointPtr->getNames();
cout << names.size() << endl;
direct = "right";
for(int i=0,index=0;i<63;++i){
const JSON::Object::Ptr &ptr = pointPtr->getObject(direct + "_eye_" + to_string(i));
x = ptr->get("x");
y = ptr->get("y");
// putText(temp, to_string(i), cvPoint(x - 10, y - 10),FONT_HERSHEY_SIMPLEX, 0.2, (0, 255, 0), 1);
// circle(temp, cvPoint(x, y), 1, cv::Scalar(0, 0, 255), -1);
srcPoints[index++] = x;
srcPoints[index++] = y;
}
right_eye_pupil_radius = pointPtr->get("right_eye_pupil_radius");
const JSON::Object::Ptr &ptr = pointPtr->getObject("right_eye_pupil_center");
right_eye_pupil_center_x = ptr->get("x");
right_eye_pupil_center_y = ptr->get("y");
// circle(temp, cvPoint(right_eye_pupil_center_x, right_eye_pupil_center_y), right_eye_pupil_radius, cv::Scalar(0, 255, 0), 1);
cout << "right_eye_pupil_radius=" << right_eye_pupil_radius << endl;
}
//Display it all on the screen
// imshow("Dlib特征点", temp);
// waitKey(0);
//美瞳
cv::Mat meitong = imread(irisPath);
unsigned char* maskData = meitong.data;
int mWidth = meitong.cols, mHeight = meitong.rows, mStride = mWidth * meitong.channels();
unsigned char* srcData = temp.data;
int width = temp.cols, height = temp.rows, stride = width * temp.channels();
f_BeautyIris(srcData,width,height,stride,srcPoints,maskData,mWidth,mHeight,mStride,NULL,100,right_eye_pupil_radius,right_eye_pupil_center_x,right_eye_pupil_center_y);
imshow("美瞳", temp);
// imwrite("/Users/edz/Downloads/右眼美瞳后.jpg",temp);
waitKey(0);
}
catch (serialization_error& e)
{
cout << "You need dlib's default face landmarking model file to run this example." << endl;
cout << "You can get it from the following URL: " << endl;
cout << " http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
cout << endl << e.what() << endl;
}
catch (exception& e)
{
cout << e.what() << endl;
}
// Mat face = imread("/Users/edz/Downloads/tongshi.png");
// imshow("face",face);
// waitKey(0);
// cout << "aaa" << endl;
}
//int f_BeautyIris(unsigned char* srcData, int width, int height, int stride, int srcPoints[], unsigned char* maskData, int mWidth, int mHeight, int mStride, int maskPoints[], int ratio)
//{
// int ret = 0;
// unsigned char* pSrc = srcData;
// int cenx = srcPoints[2 * 12];
// int ceny = srcPoints[2 * 12 + 1];
// //compute iris radius.
// int eyedistance = sqrt((float)(srcPoints[2 * 0] - srcPoints[2 * 6]) * (srcPoints[2 * 0] - srcPoints[2 * 6]) + (srcPoints[2 * 0 + 1] - srcPoints[2 * 6 + 1]) * (srcPoints[2 * 0 + 1] - srcPoints[2 * 6 + 1])) / 2;
// int irisRadius = eyedistance / 2;
// //compute the rectangle of eye area.
// int px = CLIP3(cenx - irisRadius, 0, width - 1);
// int py = CLIP3(ceny - irisRadius, 0, height - 1);
// int pmaxX = CLIP3(cenx + irisRadius, 0, width - 1);
// int pmaxY = CLIP3(ceny + irisRadius, 0, height - 1);
// int w = pmaxX - px;
// int h = pmaxY - py;
// const int pointNum = 12;
// int xPoints[pointNum];
// int yPoints[pointNum];
// int maxX = 0, minX = 100000, maxY = 0, minY = 100000;
// for(int i = 0; i < pointNum; i++)
// {
// xPoints[i] = srcPoints[2 * i];
// yPoints[i] = srcPoints[2 * i + 1];
// maxX = MAX2(srcPoints[2 * i], maxX);
// maxY = MAX2(srcPoints[2 * i + 1], maxY);
// minX = MIN2(srcPoints[2 * i], minX);
// minY = MIN2(srcPoints[2 * i + 1], minY);
// }
// //irisMask feather process
// unsigned char* irisMask = (unsigned char*)malloc(sizeof(unsigned char) * w * h * 4);
// unsigned char* pMask = irisMask;
// for(int j = 0; j < h; j++)
// {
// for(int i = 0; i < w; i++)
// {
// int dis = sqrt((float)(i - irisRadius) * (i - irisRadius) + (j - irisRadius) * (j - irisRadius));
// if(f_PNPoly_OPT(xPoints, yPoints, pointNum, i + px, j + py, minX, minY, maxX, maxY) && dis < irisRadius-3)
// pMask[0] = pMask[1] = pMask[2] = 255;
// else
// pMask[0] = pMask[1] = pMask[2] = 0;
// pMask += 4;
// }
// }
// f_FastMeanFilter(irisMask, w, h, w * 4, 3);
// pMask = irisMask;
// for(int j = 0; j < h; j++)
// {
// for(int i = 0; i < w; i++)
// {
// if(pMask[0] > 128)
// pMask[0] = pMask[1] = pMask[2] = 255;
// else
// pMask[0] = pMask[1] = pMask[2] = 0;
// pMask += 4;
// }
// }
// f_FastMeanFilter(irisMask, w, h, w * 4, 3);
// //beauty iris process
// pMask = irisMask;
// for(int j = 0; j < h; j++)
// {
// for(int i = 0; i < w; i++)
// {
// if((pMask[0] + pMask[1] + pMask[2]) / 3 > 0)
// {
// int pos_src = (px + i) * 4 + (py + j) * stride;
// int mx = i * mWidth / w;
// int my = j * mHeight / h;
// int pos_mask = mx * 4 + my * mStride;
// int r = srcData[pos_src + 2];
// int g = srcData[pos_src + 1];
// int b = srcData[pos_src];
// int mr = maskData[pos_mask + 2];
// int mg = maskData[pos_mask + 1];
// int mb = maskData[pos_mask];
// float Y, U, V, mY, mU, mV;
// //YUV
// RGB2HSB(r, g, b,&Y, &U, &V);
// RGB2HSB(mr, mg, mb, &mY, &mU, &mV);
// unsigned char R, G, B;
// HSB2RGB(mY, mU, V, &R, &G, &B);
// //feather mask process
// int a = (pMask[0] + pMask[1] + pMask[2]) / 3;
// B = CLIP3((b * (255 - a) + B * a) >> 8, 0, 255);
// G = CLIP3((g * (255 - a) + G * a) >> 8, 0, 255);
// R = CLIP3((r * (255 - a) + R * a) >> 8, 0, 255);
// //YUV color correct
// // a = CLIP3((r + g + b) / 3 * 2, 0, 255);
// //R = (R * a + r * (255 - a)) / 255;
// //G = (G * a + g * (255 - a)) / 255;
// //B = (B * a + b * (255 - a)) / 255;
// //ratio blending
// B = CLIP3((b * (100 - ratio) + B * ratio) / 100, 0, 255);
// G = CLIP3((g * (100 - ratio) + G * ratio) / 100, 0, 255);
// R = CLIP3((r * (100 - ratio) + R * ratio) / 100, 0, 255);
//
// srcData[pos_src] = B;
// srcData[pos_src + 1] = G;
// srcData[pos_src + 2] = R;
// }
// pMask += 4;
// }
// }
// free(irisMask);
// return ret;
//};
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: BeautyIris .
*************************************************************************/
#ifndef __T_BEAUTY_IRIS__
#define __T_BEAUTY_IRIS__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: BeautyIris
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcPoints: 12 eyepoints and one center points
*maskData: 32BGRA mask image buffer
*mWidth: width of mask
*mHeight:height of mask
*mStride:Stride of mask
*maskPoints: 12 eyepoints and one center points of mask image
*ratio: intensity of iris, [0,100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_BeautyIris(unsigned char* srcData, int width, int height, int stride, int srcPoints[], unsigned char* maskData, int mWidth, int mHeight, int mStride, int maskPoints[], int ratio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_BeautyIris(unsigned char* srcData, int width, int height, int stride, int srcPoints[], unsigned char* maskData, int mWidth, int mHeight, int mStride, int maskPoints[], int ratio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include<math.h>
int ModeLinearLight(int basePixel,int mixPixel)
{
int res = 0;
res = 2 * mixPixel + basePixel - 256;
return CLIP3(res, 0, 255);
};
int ModeSuperposition(int basePixel,int mixPixel)//基色 < = 128:结果色 = 混合色 * 基色 / 128;基色 > 128:结果色 = 255 - (255 - 混合色)* (255 - 基色) / 128
{
int res = 0;
res = ((basePixel <= 128) ? (mixPixel * basePixel / 128):(255 - (255 - mixPixel) * (255 - basePixel) / 128));
return CLIP3(res, 0, 255);
};
\ No newline at end of file
#ifndef __COMMEN_MIX_LAYER__
#define __COMMEN_MIX_LAYER__
int ModeLinearLight(int basePixel,int mixPixel);//线性光
int ModeSuperposition(int basePixel,int mixPixel);//叠加//基色 < = 128:结果色 = 混合色 * 基色 / 128;基色 > 128:结果色 = 255 - (255 - 混合色)* (255 - 基色) / 128
#endif
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,12 +2,12 @@
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Date: 2019-6-23
Mail: dongtingyueh@163.com
Description: Skin Color.
Description: FACE EYELID .
*************************************************************************/
#ifndef __T_SKIN_COLOR__
#define __T_SKIN_COLOR__
#ifndef __T_MAKEUP_FACE_EYELID__
#define __T_MAKEUP_FACE_EYELID__
#ifdef _MSC_VER
......@@ -17,20 +17,24 @@ Description: Skin Color.
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SKIN COLOR
*Function: EyeLid
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*skinMask: skin mask
*lutData: 32BGRA buffer of lut image.
*ratio: Intensity of skin colored,range [0,100]
*srcFacePoints: 101 face points.
*mskData: EyeLid image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints: 3 key points of eyelid mask.
*isLeft: left or right face.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_SkinColor(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio);
EXPORT int f_EyeLid(unsigned char* srcData, int width, int height, int stride, int srcFacePoints[202], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], bool isLeft, int ratio);
#else
......@@ -38,7 +42,8 @@ EXPORT int f_SkinColor(unsigned char* srcData, int width, int height, int stride
extern "C" {
#endif
int f_SkinColor(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio);
int f_EyeLid(unsigned char* srcData, int width, int height, int stride, int srcFacePoints[202], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], bool isLeft, int ratio);
#ifdef __cplusplus
}
#endif
......
#include"f_GaussFilter.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include"Commen.h"
/*************************************************************
*Function: Gauss mask compute
*Params:
* r-radius of gauss filter
* sigma-sigma of gauss filter
* gaussMask-gauss weight to compute with size of (2r+1)*(2r+1)
*Return NULL
************************************************************/
void GaussMask(int r, double sigma, double gaussMask[])
{
double PI = 3.1415926;
double sum = 0;
int stride = 2 * r + 1;
for (int y = -r, h = 0; y <= r; y++, h++)
{
for (int x = -r, w = 0; x <= r; x++, w++)
{
gaussMask[w + h * stride] = (1.0 / (2.0 * PI * sigma * sigma)) * (exp(-((double)x * (double)x + (double)y * (double)y) / (2.0 * sigma * sigma)));
sum += gaussMask[w + h * stride];
}
}
for (int i = 0; i < stride * stride; i++)
{
gaussMask[i] = gaussMask[i] / sum;
}
};
int f_FastGaussFilter(unsigned char* srcData,int width, int height,int stride,float r)
{
int ret = 0;
int radius = (int)r;
if(r == 0)
return ret;
unsigned char* dstData = (unsigned char*)malloc(sizeof(unsigned char)*height*stride);
unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char)*height*stride);
int totalWei = 0;
int i,j,k;
float sigma = r;
unsigned char *kernel = (unsigned char *)malloc(2*radius+1);
for (i = -radius; i <= radius; i++)
{
kernel[i+radius] = (unsigned char) (exp(-(float)i*i/(2*sigma*sigma))*128);
totalWei += kernel[i+radius];
}
int tempR = 0, tempG = 0, tempB = 0;
int v = 0;
int K = 0;
int rem = 0;
int t = 0;
int offset = stride - width * 4;
for ( j = 0; j < height; j++)
{
for ( i = 0; i < width; i++)
{
tempR = 0; tempG = 0; tempB = 0;
for ( k = -radius; k <= radius; k++)
{
rem = (abs(i + k) % width);
t = rem * 3 + j * stride;
K = kernel[k + radius];
tempB += srcData[t] * K;
tempG += srcData[t + 1] * K;
tempR += srcData[t + 2] * K;
}
v = i * 3 + j * stride;
tempData[v] = tempB / totalWei;
tempData[v + 1] = tempG / totalWei;
tempData[v + 2] = tempR / totalWei;
}
}
for ( i = 0; i < width; i++)
{
for ( j = 0; j < height; j++)
{
tempR = 0; tempG = 0; tempB = 0;
for ( k = -radius; k <= radius; k++)
{
rem = (abs(j + k) % height);
t = rem * stride + i * 3;
K = kernel[k + radius];
tempB += tempData[t] * K;
tempG += tempData[t + 1] * K;
tempR += tempData[t + 2] * K;
}
v = i * 3 + j * stride;
dstData[v] = tempB/totalWei;
dstData[v + 1] = tempG/totalWei;
dstData[v + 2] = tempR/totalWei;
}
}
memcpy(srcData, dstData, sizeof(unsigned char) * height * stride);
free(dstData);
free(tempData);
return ret;
};
\ No newline at end of file
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: Gauss Filter
*************************************************************************/
#ifndef __TEST_GAUSSFILTER__
#define __TEST_GAUSSFILTER__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/************************************************************
*Function: Gauss Filter
*Description: Gauss Filter process
*Params:
*srcData: image bgra data
*width :image width
*height :image height
*stride :image stride
*r: radius of gauss filter, range [0,]
*Return :0-OK,or failed
************************************************************/
EXPORT int f_FastGaussFilter(unsigned char* srcData,int width, int height,int stride,float r);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_FastGaussFilter(unsigned char* srcData,int width, int height,int stride,float r);
////
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"f_LUTFilter.h"
#include"Commen.h"
static int f_Filter512(unsigned char* srcData, int width ,int height, int stride, unsigned char*Map)
{
int i, j, r, g, b, offset, pos, nx, ny, k;
unsigned char* pSrc = srcData;
offset = stride - (width * 4);
for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
b = pSrc[0];
g = pSrc[1];
r = pSrc[2];
k = (b >> 2);
nx = (int)(r >> 2) + ((k - ((k >> 3) << 3)) << 6);
ny = (int)(((b >> 5) << 6) + (g >> 2));
pos = (nx * 4) + (ny * 512 * 4);
pSrc[0] = Map[pos];
pSrc[1] = Map[pos + 1];
pSrc[2] = Map[pos + 2];
pSrc += 4;
}
pSrc += offset;
}
return 0;
};
int f_LUTFilter(unsigned char *srcData, int width, int height, int stride,unsigned char* Map)
{
return f_Filter512(srcData, width, height, stride, Map);
};
\ No newline at end of file
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: LUT Filter
*************************************************************************/
#ifndef __TEST_LUT_FILTER__
#define __TEST_LUT_FILTER__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/************************************************************
*Function: LUT Filter
*Description: LUT Filter process
*Params:
*srcData: image bgr data
*width :image width
*height :image height
*stride :image stride
*Map: 512x512 LUT
*Return :0-OK,or failed
************************************************************/
EXPORT int f_LUTFilter(unsigned char *srcData, int width, int height, int stride, unsigned char* Map);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_LUTFilter(unsigned char *srcData, int width, int height, int stride, unsigned char* Map);
////
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"f_LaplaceSharpen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include"Commen.h"
int f_LaplaceSharpen(unsigned char* srcData,int width, int height,int stride,int mode)
{
int ret = 0;
unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
int offset = stride - width * 4;
int pos;
memcpy(tempData, srcData, sizeof(unsigned char) * height * stride);
if(mode == 0)
{
for(int j = 1; j < height - 1; j++)
{
for(int i = 1; i < width - 1; i++)
{
pos = i * 3 + j * stride;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 4 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride]), 0, 255);
pos++;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 4 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride]), 0, 255);
pos++;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 4 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride]), 0, 255);
}
}
}
else
{
for(int j = 1; j < height - 1; j++)
{
for(int i = 1; i < width - 1; i++)
{
pos = i * 3 + j * stride;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 6 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride] - tempData[pos - 3 - stride] - tempData[pos + 3 - stride] - tempData[pos - 3 + stride] - tempData[pos + 3 + stride]), 0, 255);
pos++;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 6 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride] - tempData[pos - 3 - stride] - tempData[pos + 3 - stride] - tempData[pos - 3 + stride] - tempData[pos + 3 + stride]), 0, 255);
pos++;
srcData[pos] = CLIP3(tempData[pos] + (tempData[pos] * 6 - tempData[pos - stride] - tempData[pos - 3] - tempData[pos + 3] - tempData[pos + stride] - tempData[pos - 3 - stride] - tempData[pos + 3 - stride] - tempData[pos - 3 + stride] - tempData[pos + 3 + stride]), 0, 255);
}
}
}
free(tempData);
return ret;
};
\ No newline at end of file
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: Laplace sharpen
*************************************************************************/
#ifndef __TEST_LAPLACE_SHARPEN__
#define __TEST_LAPLACE_SHARPEN__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/************************************************************
*Function: Laplace sharpen
*Description: Laplace sharpen process
*Params:
*srcData: image bgra data
*width :image width
*height :image height
*stride :image stride
*mode :0-MASK4,1-MASK8
*Return :0-OK,or failed
************************************************************/
EXPORT int f_LaplaceSharpen(unsigned char* srcData,int width, int height,int stride,int mode);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_LaplaceSharpen(unsigned char* srcData,int width, int height,int stride,int mode);
////
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include"f_MakeupBase.h"
#include"f_AffineTransfrom.h"
#include<math.h>
#include "vector"
#include "opencv4/opencv2/opencv.hpp"
/*************************************************************************
*Function: Makeup base with Nearest Neighbour Interpolation
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcKeyPoints: 3 key points of source image.
*mskData: mask image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints�� 3 key points of blush mask.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
int f_MakeupBaseN(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio)
{
int ret = 0;
float H[6] = {0};
f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[2],(float)maskKeyPoints[3],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[2], (float)srcKeyPoints[3], (float)srcKeyPoints[4], (float)srcKeyPoints[5], H);
unsigned char* pSrc = srcData;
int alpha = 128 * ratio / 100;
int nalpha = 128 - alpha;
int AR, AG, AB, AA;
int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
int disX, disY, tmp1, tmp2;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int x0 = (H[0] * i + H[1] * j + H[2]);
int y0 = (H[3] * i + H[4] * j + H[5]);
if(x0 > 0 && x0 < mWidth - 1 && y0 > 0 && y0 < mHeight - 1)
{
int pos = (x0 << 2) + y0 * mStride;
int k = mskData[pos + 3];
int b = (k * mskData[pos] + (255 - k) * pSrc[0]) / 255;
int g = (k * mskData[pos + 1] + (255 - k) * pSrc[1]) / 255;
int r = (k * mskData[pos + 2] + (255 - k) * pSrc[2]) / 255;
pSrc[0] = ((alpha * b + nalpha * pSrc[0]) >> 7);
pSrc[1] = ((alpha * g + nalpha * pSrc[1]) >> 7);
pSrc[2] = ((alpha * r + nalpha * pSrc[2]) >> 7);
}
pSrc += 4;
}
}
return ret;
};
/*************************************************************************
*Function: Makeup base with bilinear interpolation
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcKeyPoints: 3 key points of source image.
*mskData: mask image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints�� 3 key points of blush mask.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
//int f_MakeupBase(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio)
//{
// int ret = 0;
// float H[6] = {0};
// f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[2],(float)maskKeyPoints[3],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[2], (float)srcKeyPoints[3], (float)srcKeyPoints[4], (float)srcKeyPoints[5], H);
// unsigned char* pSrc = srcData;
// int alpha = 128 * ratio / 100;
// int nalpha = 128 - alpha;
// int AR, AG, AB, AA;
// int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
// int disX, disY, tmp1, tmp2;
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// float cx = (H[0] * i + H[1] * j + H[2]);
// float cy = (H[3] * i + H[4] * j + H[5]);
// if(cx > 0 && cx < mWidth - 1 && cy > 0 && cy < mHeight - 1)
// {
//
// x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
// y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
// index_x0y0 = (x0 << 2) + y0 * mStride;
// index_x1y0 = index_x0y0 + 4;
// index_x0y1 = index_x0y0 + mStride;
// index_x1y1 = index_x0y1 + 4;
// disX = (int)((cx - x0) * 16384);
// disY = (int)((cy - y0) * 16384);
// tmp1 = mskData[index_x0y0] + ((disX *(mskData[index_x1y0] - mskData[index_x0y0])) >> 14);
// tmp2 = mskData[index_x0y1] + ((disX *(mskData[index_x1y1] - mskData[index_x0y1])) >> 14);
// AB = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 1] + ((disX *(mskData[index_x1y0 + 1] - mskData[index_x0y0 + 1])) >> 14);
// tmp2 = mskData[index_x0y1 + 1] + ((disX *(mskData[index_x1y1 + 1] - mskData[index_x0y1 + 1])) >> 14);
// AG = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 2] + ((disX *(mskData[index_x1y0 + 2] - mskData[index_x0y0 + 2])) >> 14);
// tmp2 = mskData[index_x0y1 + 2] + ((disX *(mskData[index_x1y1 + 2] - mskData[index_x0y1 + 2])) >> 14);
// AR = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 3] + ((disX *(mskData[index_x1y0 + 3] - mskData[index_x0y0 + 3])) >> 14);
// tmp2 = mskData[index_x0y1 + 3] + ((disX *(mskData[index_x1y1 + 3] - mskData[index_x0y1 + 3])) >> 14);
// AA = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
//
// int pos = (x0 << 2) + y0 * mStride;
// int k = AA;
// int b = (k * AB + (255 - k) * pSrc[0]) / 255;
// int g = (k * AG + (255 - k) * pSrc[1]) / 255;
// int r = (k * AR + (255 - k) * pSrc[2]) / 255;
// pSrc[0] = ((alpha * b + nalpha * pSrc[0]) >> 7);
// pSrc[1] = ((alpha * g + nalpha * pSrc[1]) >> 7);
// pSrc[2] = ((alpha * r + nalpha * pSrc[2]) >> 7);
// }
// pSrc += 4;
// }
// }
// return ret;
//};
//int f_MakeupBase(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio)
//{
// int ret = 0;
// float H[6] = {0};
// f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[2],(float)maskKeyPoints[3],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[2], (float)srcKeyPoints[3], (float)srcKeyPoints[4], (float)srcKeyPoints[5], H);
// unsigned char* pSrc = srcData;
// int alpha = 128 * ratio / 100;
// int nalpha = 128 - alpha;
// int AR, AG, AB, AA;
// int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
// int disX, disY, tmp1, tmp2;
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// float cx = (H[0] * i + H[1] * j + H[2]);
// float cy = (H[3] * i + H[4] * j + H[5]);
// if(cx > 0 && cx < mWidth - 1 && cy > 0 && cy < mHeight - 1)
// {
//
// x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
// y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
// index_x0y0 = (x0 << 2) + y0 * mStride;
// index_x1y0 = index_x0y0 + 4;
// index_x0y1 = index_x0y0 + mStride;
// index_x1y1 = index_x0y1 + 4;
// disX = (int)((cx - x0) * 16384);
// disY = (int)((cy - y0) * 16384);
// tmp1 = mskData[index_x0y0] + ((disX *(mskData[index_x1y0] - mskData[index_x0y0])) >> 14);
// tmp2 = mskData[index_x0y1] + ((disX *(mskData[index_x1y1] - mskData[index_x0y1])) >> 14);
// AB = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 1] + ((disX *(mskData[index_x1y0 + 1] - mskData[index_x0y0 + 1])) >> 14);
// tmp2 = mskData[index_x0y1 + 1] + ((disX *(mskData[index_x1y1 + 1] - mskData[index_x0y1 + 1])) >> 14);
// AG = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 2] + ((disX *(mskData[index_x1y0 + 2] - mskData[index_x0y0 + 2])) >> 14);
// tmp2 = mskData[index_x0y1 + 2] + ((disX *(mskData[index_x1y1 + 2] - mskData[index_x0y1 + 2])) >> 14);
// AR = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
// tmp1 = mskData[index_x0y0 + 3] + ((disX *(mskData[index_x1y0 + 3] - mskData[index_x0y0 + 3])) >> 14);
// tmp2 = mskData[index_x0y1 + 3] + ((disX *(mskData[index_x1y1 + 3] - mskData[index_x0y1 + 3])) >> 14);
// AA = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
//
// int pos = (x0 << 2) + y0 * mStride;
// int k = AA;
// int b = (k * AB + (255 - k) * pSrc[0]) / 255;
// int g = (k * AG + (255 - k) * pSrc[1]) / 255;
// int r = (k * AR + (255 - k) * pSrc[2]) / 255;
// pSrc[0] = ((alpha * b + nalpha * pSrc[0]) >> 7);
// pSrc[1] = ((alpha * g + nalpha * pSrc[1]) >> 7);
// pSrc[2] = ((alpha * r + nalpha * pSrc[2]) >> 7);
// }
// pSrc += 3;
// }
// }
// return ret;
//};
inline bool f_IsBelowLine(int inputPoint[4], float x, float y)
{
int x1 = inputPoint[0];
int y1 = inputPoint[1];
int x2 = inputPoint[2];
int y2 = inputPoint[3];
float val = (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1);
return (val > 0);
};
int f_MakeupBase(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio)
{
int ret = 0;
float H[6] = {0};
f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[2],(float)maskKeyPoints[3],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[2], (float)srcKeyPoints[3], (float)srcKeyPoints[4], (float)srcKeyPoints[5], H);
unsigned char* pSrc = srcData;
int alpha = 128 * ratio / 100;
int nalpha = 128 - alpha;
int Line[4] = {srcKeyPoints[0], srcKeyPoints[1], srcKeyPoints[4], srcKeyPoints[5]};
int AR, AG, AB, AA;
int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
int disX, disY, tmp1, tmp2;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
bool isBelowLine = f_IsBelowLine(Line, i, j);
float cx = 0, cy = 0;
if(!isBelowLine)
{
cx = (H[0] * i + H[1] * j + H[2]);
cy = (H[3] * i + H[4] * j + H[5]);
}
else
{
cx = (H[0] * i + H[1] * j + H[2]);
cy = (H[3] * i + H[4] * j + H[5]);
}
if(cx > 0 && cy < mWidth - 1 && cx > 0 && cy < mHeight - 1)
{
x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
index_x0y0 = (x0 << 2) + y0 * mStride;
index_x1y0 = index_x0y0 + 4;
index_x0y1 = index_x0y0 + mStride;
index_x1y1 = index_x0y1 + 4;
disX = (int)((cx - x0) * 16384);
disY = (int)((cy - y0) * 16384);
tmp1 = mskData[index_x0y0] + ((disX *(mskData[index_x1y0] - mskData[index_x0y0])) >> 14);
tmp2 = mskData[index_x0y1] + ((disX *(mskData[index_x1y1] - mskData[index_x0y1])) >> 14);
AB = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 1] + ((disX *(mskData[index_x1y0 + 1] - mskData[index_x0y0 + 1])) >> 14);
tmp2 = mskData[index_x0y1 + 1] + ((disX *(mskData[index_x1y1 + 1] - mskData[index_x0y1 + 1])) >> 14);
AG = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 2] + ((disX *(mskData[index_x1y0 + 2] - mskData[index_x0y0 + 2])) >> 14);
tmp2 = mskData[index_x0y1 + 2] + ((disX *(mskData[index_x1y1 + 2] - mskData[index_x0y1 + 2])) >> 14);
AR = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 3] + ((disX *(mskData[index_x1y0 + 3] - mskData[index_x0y0 + 3])) >> 14);
tmp2 = mskData[index_x0y1 + 3] + ((disX *(mskData[index_x1y1 + 3] - mskData[index_x0y1 + 3])) >> 14);
AA = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
if (AA != 0)
{
int mb = AB;
int mg = AG;
int mr = AR;
mb = (mb * AA + pSrc[0] * (255 - AA)) / 255;
mg = (mg * AA + pSrc[1] * (255 - AA)) / 255;
mr = (mr * AA + pSrc[2] * (255 - AA)) / 255;
pSrc[0] = (pSrc[0] * (100 - ratio) + mb * ratio) / 100;
pSrc[1] = (pSrc[1] * (100 - ratio) + mg * ratio) / 100;
pSrc[2] = (pSrc[2] * (100 - ratio) + mr * ratio) / 100;
}
}
pSrc += 3;
}
}
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// float cx = (H[0] * i + H[1] * j + H[2]);
// float cy = (H[3] * i + H[4] * j + H[5]);
// if(cx > 0 && cx < mWidth - 1 && cy > 0 && cy < mHeight - 1)
// {
// x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
// y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
// int pos = x0 * 3 + y0 * mStride;
// if(mskData[pos+3]>0){
//// pSrc[0] = mskData[pos];
//// pSrc[1] = mskData[pos+1];
//// pSrc[2] = mskData[pos+2];
// pSrc[0] = (alpha * mskData[pos] + nalpha * pSrc[0]) >> 7;
// pSrc[1] = (alpha * mskData[pos+1] + nalpha * pSrc[1]) >> 7;
// pSrc[2] = (alpha * mskData[pos+2] + nalpha * pSrc[2]) >> 7;
//
// }
// }
// pSrc += 3;
// }
// }
return ret;
};
//int f_MakeupBase(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio)
//{
// int ret = 0;
// unsigned char* pSrc = srcData;
// int alpha = 128 * ratio / 100;
// int nalpha = 128 - alpha;
// int x0, y0;
// for(int j = 0; j < height; j++)
// {
// for(int i = 0; i < width; i++)
// {
// float cx = i;
// float cy = j;
// if(cx > 0 && cx < mWidth - 1 && cy > 0 && cy < mHeight - 1)
// {
// x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
// y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
// int pos = x0 * 4 + y0 * mStride;
// if(mskData[pos+3]>0){
//// pSrc[0] = mskData[pos];
//// pSrc[1] = mskData[pos+1];
//// pSrc[2] = mskData[pos+2];
// pSrc[0] = 255;
// pSrc[1] = 255;
// pSrc[2] = 255;
//
// }
// }
// pSrc += 3;
// }
// }
// return ret;
//};
inline int ModeSmoothLight(int basePixel,int mixPixel)
{
int res = 0;
res = mixPixel > 128 ? ((int)((float)basePixel+((float)mixPixel+(float)mixPixel-255.0f)*((sqrt((float)basePixel/255.0f))*255.0f-(float)basePixel)/255.0f)):
((int)((float)basePixel+((float)mixPixel+(float)mixPixel-255.0f)*((float)basePixel-(float)basePixel*(float)basePixel/255.0f)/255.0f));
return CLIP3(res, 0, 255);
};
/*************************************************************************
*Function: f_MakeupBaseShadow
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcKeyPoints: 4 key points of source image.
*mskData: blush image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints�� 4 key points of blush mask.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
int f_MakeupBaseShadow(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 4], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 4], int mode, int ratio)
{
int ret = 0;
float HU[6] = {0}, HD[6] = {0};
f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[2],(float)maskKeyPoints[3],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[2], (float)srcKeyPoints[3], (float)srcKeyPoints[4], (float)srcKeyPoints[5], HU);
f_AffinetransformMetrixCompute((float)maskKeyPoints[0],(float)maskKeyPoints[1],(float)maskKeyPoints[6],(float)maskKeyPoints[7],(float)maskKeyPoints[4],(float)maskKeyPoints[5], (float)srcKeyPoints[0], (float)srcKeyPoints[1], (float)srcKeyPoints[6], (float)srcKeyPoints[7], (float)srcKeyPoints[4], (float)srcKeyPoints[5], HD);
unsigned char* pSrc = srcData;
int alpha = 128 * ratio / 100;
int nalpha = 128 - alpha;
int Line[4] = {srcKeyPoints[0], srcKeyPoints[1], srcKeyPoints[4], srcKeyPoints[5]};
int AR, AG, AB, AA;
int x0, y0, index_x0y0, index_x0y1, index_x1y0, index_x1y1;
int disX, disY, tmp1, tmp2;
if(mode == 0)
{
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
bool isBelowLine = f_IsBelowLine(Line, i, j);
float cx = 0, cy = 0;
if(!isBelowLine)
{
cx = (HU[0] * i + HU[1] * j + HU[2]);
cy = (HU[3] * i + HU[4] * j + HU[5]);
}
else
{
cx = (HD[0] * i + HD[1] * j + HD[2]);
cy = (HD[3] * i + HD[4] * j + HD[5]);
}
if(cx > 0 && cy < mWidth - 1 && cx > 0 && cy < mHeight - 1)
{
x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
index_x0y0 = (x0 << 2) + y0 * mStride;
index_x1y0 = index_x0y0 + 4;
index_x0y1 = index_x0y0 + mStride;
index_x1y1 = index_x0y1 + 4;
disX = (int)((cx - x0) * 16384);
disY = (int)((cy - y0) * 16384);
tmp1 = mskData[index_x0y0] + ((disX *(mskData[index_x1y0] - mskData[index_x0y0])) >> 14);
tmp2 = mskData[index_x0y1] + ((disX *(mskData[index_x1y1] - mskData[index_x0y1])) >> 14);
AB = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 1] + ((disX *(mskData[index_x1y0 + 1] - mskData[index_x0y0 + 1])) >> 14);
tmp2 = mskData[index_x0y1 + 1] + ((disX *(mskData[index_x1y1 + 1] - mskData[index_x0y1 + 1])) >> 14);
AG = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 2] + ((disX *(mskData[index_x1y0 + 2] - mskData[index_x0y0 + 2])) >> 14);
tmp2 = mskData[index_x0y1 + 2] + ((disX *(mskData[index_x1y1 + 2] - mskData[index_x0y1 + 2])) >> 14);
AR = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 3] + ((disX *(mskData[index_x1y0 + 3] - mskData[index_x0y0 + 3])) >> 14);
tmp2 = mskData[index_x0y1 + 3] + ((disX *(mskData[index_x1y1 + 3] - mskData[index_x0y1 + 3])) >> 14);
AA = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
if (AA != 0)
{
int mb = AB;
int mg = AG;
int mr = AR;
mb = (mb * AA + pSrc[0] * (255 - AA)) / 255;
mg = (mg * AA + pSrc[1] * (255 - AA)) / 255;
mr = (mr * AA + pSrc[2] * (255 - AA)) / 255;
pSrc[0] = (pSrc[0] * (100 - ratio) + mb * ratio) / 100;
pSrc[1] = (pSrc[1] * (100 - ratio) + mg * ratio) / 100;
pSrc[2] = (pSrc[2] * (100 - ratio) + mr * ratio) / 100;
}
}
pSrc += 4;
}
}
}
else
{
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
bool isBelowLine = f_IsBelowLine(Line, i, j);
float cx = 0, cy = 0;
if(!isBelowLine)
{
cx = (HU[0] * i + HU[1] * j + HU[2]);
cy = (HU[3] * i + HU[4] * j + HU[5]);
}
else
{
cx = (HD[0] * i + HD[1] * j + HD[2]);
cy = (HD[3] * i + HD[4] * j + HD[5]);
}
if(cx > 0 && cx < mWidth - 1 && cy > 0 && cy < mHeight - 1)
{
x0 = (int)CLIP3(floor(cx), 0, mWidth - 2);
y0 = (int)CLIP3(floor(cy), 0, mHeight - 2);
index_x0y0 = (x0 << 2) + y0 * mStride;
index_x1y0 = index_x0y0 + 4;
index_x0y1 = index_x0y0 + mStride;
index_x1y1 = index_x0y1 + 4;
disX = (int)((cx - x0) * 16384);
disY = (int)((cy - y0) * 16384);
tmp1 = mskData[index_x0y0] + ((disX *(mskData[index_x1y0] - mskData[index_x0y0])) >> 14);
tmp2 = mskData[index_x0y1] + ((disX *(mskData[index_x1y1] - mskData[index_x0y1])) >> 14);
AB = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 1] + ((disX *(mskData[index_x1y0 + 1] - mskData[index_x0y0 + 1])) >> 14);
tmp2 = mskData[index_x0y1 + 1] + ((disX *(mskData[index_x1y1 + 1] - mskData[index_x0y1 + 1])) >> 14);
AG = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 2] + ((disX *(mskData[index_x1y0 + 2] - mskData[index_x0y0 + 2])) >> 14);
tmp2 = mskData[index_x0y1 + 2] + ((disX *(mskData[index_x1y1 + 2] - mskData[index_x0y1 + 2])) >> 14);
AR = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
tmp1 = mskData[index_x0y0 + 3] + ((disX *(mskData[index_x1y0 + 3] - mskData[index_x0y0 + 3])) >> 14);
tmp2 = mskData[index_x0y1 + 3] + ((disX *(mskData[index_x1y1 + 3] - mskData[index_x0y1 + 3])) >> 14);
AA = tmp1 + ((disY * (tmp2 - tmp1)) >> 14);
if (AA != 0)
{
int mb = AB;
int mg = AG;
int mr = AR;
int b = ModeSmoothLight(pSrc[0], mb);
int g = ModeSmoothLight(pSrc[1], mg);
int r = ModeSmoothLight(pSrc[2], mr);
b = (b * AA + pSrc[0] * (255 - AA)) / 255;
g = (g * AA + pSrc[1] * (255 - AA)) / 255;
r = (r * AA + pSrc[2] * (255 - AA)) / 255;
pSrc[0] = (pSrc[0] * (100 - ratio) + b * ratio) / 100;
pSrc[1] = (pSrc[1] * (100 - ratio) + g * ratio) / 100;
pSrc[2] = (pSrc[2] * (100 - ratio) + r * ratio) / 100;
}
}
pSrc += 4;
}
}
}
return ret;
};
\ No newline at end of file
#ifndef __T_MAKEUP_BASE__
#define __T_MAKEUP_BASE__
/*************************************************************************
*Function: Makeup base
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcFacePoints: 101 face points.
*mskData: mask image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints 3 key points of mask mask.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
int f_MakeupBase(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 3], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 3], int ratio);
/*************************************************************************
*Function: f_MakeupBaseShadow
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*srcKeyPoints: 4 key points of source image.
*mskData: eyeshadow image buffer with format bgra32
*mWidth: width of mask image
*mHeight: height of mask image
*mStride: Stride of mask image
*maskKeyPoints 4 key points of eyeshadow mask.
*mode: overlay mode.
*ratio: intensity of effect, [0, 100]
*Return: 0-OK,other failed
**************************************************************************/
int f_MakeupBaseShadow(unsigned char* srcData, int width, int height, int stride, int srcKeyPoints[2 * 4], unsigned char* mskData, int mWidth, int mHeight, int mStride, int maskKeyPoints[2 * 4], int mode, int ratio);
#endif
\ No newline at end of file
#include"f_MeanFilter.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include"Commen.h"
//Fast mean filter based histagram computation
int f_FastMeanFilter(unsigned char* srcData, int width, int height ,int stride, int radius)
{
int ret = 0;
if(radius == 0)
return ret;
if(radius > MIN2(width,height) / 2)
radius = (MIN2(width, height) / 2-0.5);
unsigned char* dstData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
int unit = 3, t = 0, t1 = 0;
int i,j,k,len = width * height * unit;
int block = (radius << 1) + 1;
int winSize = block * block;
long sumB = 0, sumG = 0,sumR = 0;
unsigned char* pSrc = srcData;
int* temp = (int*)malloc(sizeof(int)* width * unit);
memset(temp,0,sizeof(int) * width * unit);
for(k = -radius; k <= radius; k++)
{
for(j = 0; j< width; j++)
{
t = j * unit;
t1 = abs(k) * stride;
temp[t] += pSrc[t + t1];
temp[t + 1] += pSrc[t + 1 + t1];
temp[t + 2] += pSrc[t + 2 + t1];
}
}
for (i = 0; i < height; i++)
{
sumB = sumG = sumR = 0;
for (j = -radius; j <= radius; j++)
{
t = abs(j) * unit;
sumB += temp[t];
sumG += temp[t + 1];
sumR += temp[t + 2];
}
for (j = 0; j < width; j++)
{
t = j * unit + i * stride;
dstData[t] = (sumB / winSize);
dstData[t + 1] = (sumG / winSize);
dstData[t + 2] = (sumR / winSize);
if (j < width - 1)
{
t = abs(j - radius) * unit;
t1 = (j + radius + 1) % width * unit;
sumB = sumB - temp[t] + temp[t1];
sumG = sumG - temp[t + 1] + temp[t1 + 1];
sumR = sumR - temp[t + 2] + temp[t1 + 2];
}
}
if (i < height - 1)
{
for (k = 0; k < width; k++)
{
t = k * unit + abs(i - radius) * stride;
t1 = k * unit + (i + radius + 1) % height * stride;
temp[k * unit] = temp[k * unit] - pSrc[t] + pSrc[t1];
temp[k * unit + 1] = temp[k * unit + 1] - pSrc[t + 1] + pSrc[t1 + 1];
temp[k * unit + 2] = temp[k * unit + 2] - pSrc[t + 2] + pSrc[t1 + 2];
}
}
}
memcpy(srcData, dstData, sizeof(unsigned char) * height * stride);
free(dstData);
free(temp);
return ret;
};
//std mean filter
int f_MeanFilter(unsigned char *srcData, int width, int height, int stride, int radius)
{
int ret = 0;
if(radius == 0)
return ret;
int offset = stride - width * 4;
unsigned char* temp = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
memcpy(temp, srcData, sizeof(unsigned char) * height * stride);
int M = (radius * 2 + 1) * (radius * 2 + 1);
int sumr = 0, sumg = 0, sumb = 0;
unsigned char* pSrc = srcData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
sumr = sumg = sumb = 0;
for(int n = -radius; n <=radius; n++)
{
for(int m = -radius; m <= radius; m++)
{
int ny = CLIP3(j + n, 0, height - 1);
int nx = CLIP3(i + m, 0, width - 1);
int pos = nx * 4 + ny * stride;
sumb += temp[pos];
sumg += temp[pos + 1];
sumr += temp[pos + 2];
}
}
pSrc[0] = sumb / M;
pSrc[1] = sumg / M;
pSrc[2] = sumr / M;
pSrc += 4;
}
pSrc += offset;
}
free(temp);
return ret;
};
/*************************************************************************
Copyright: Trent.
Author: Trent1985
Date: 2018-9-23
Mail: dongtingyueh@163.com
Description: Mean Filter
*************************************************************************/
#ifndef __TEST_MEANFILTER__
#define __TEST_MEANFILTER__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/************************************************************
*Function: Mean Filter
*Description: Mean Filter process
*Params:
*srcData: image bgr data
*width :image width
*height :image height
*stride :image stride
*radius: range [0,]
*Return :0-OK,or failed
************************************************************/
EXPORT int f_MeanFilter(unsigned char *srcData, int width, int height, int stride, int radius);
/************************************************************
*Function: Fast Mean Filter
*Description: Fast Mean Filter process
*Params:
*srcData: image bgr data
*width :image width
*height :image height
*stride :image stride
*radius: range [0,]
*Return :0-OK,or failed
************************************************************/
EXPORT int f_FastMeanFilter(unsigned char* srcData, int width, int height ,int stride, int radius);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_MeanFilter(unsigned char *srcData, int width, int height, int stride, int radius);
int f_FastMeanFilter(unsigned char* srcData, int width, int height ,int stride, int radius);
////
#ifdef __cplusplus
}
#endif
#endif
#endif
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"Commen.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h"
#include"f_GaussFilter.h"
#include"f_SkinColor.h"
/*************************************************************************
*Function: SKIN COLOR
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*skinMask: skin mask
*lutData: 32BGRA buffer of lut image.
*ratio: Intensity of skin colored,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_SkinColor(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(tempData, srcData, sizeof(unsigned char) * length);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(skinPDF, srcData, sizeof(unsigned char) * length);
ret = f_SkinPDF(skinPDF, width, height, stride);
int maskSmoothRadius = 3;
ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
ret = f_LUTFilter(tempData, width, height, stride, lutData);
unsigned char* pSrc = srcData;
unsigned char* pLut = tempData;
unsigned char* pSkin = skinPDF;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int r, g, b, a;
b = CLIP3((pSrc[0] * (100 - ratio) + pLut[0] * ratio) / 100, 0, 255);
g = CLIP3((pSrc[1] * (100 - ratio) + pLut[1] * ratio) / 100, 0, 255);
r = CLIP3((pSrc[2] * (100 - ratio) + pLut[2] * ratio) / 100, 0, 255);
a = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
pSrc[0] = CLIP3((b * a + pSrc[0] * (255 - a)) / 255, 0, 255);
pSrc[1] = CLIP3((g * a + pSrc[1] * (255 - a)) / 255, 0, 255);
pSrc[2] = CLIP3((r * a + pSrc[2] * (255 - a)) / 255, 0, 255);
pSrc += 4;
pLut += 4;
pSkin += 4;
}
}
free(tempData);
free(skinPDF);
return ret;
};
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include"f_SkinPDF.h"
#include"TRGB2YCbCr.h"
#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define CLIP3(x, a, b) MIN2(MAX2(a,x), b)
float Gaussian(float x, float mean, float var)
{
float t = -0.5f * (x - mean) * (x - mean) / var;
return exp(t);
}
float GetPDF(int R, int G, int B, float meanCb, float varCb, float meanCr, float varCr)
{
int Y, Cb, Cr;
RGBToYCbCr(R, G, B, &Y, &Cb, &Cr);
float pcb = Gaussian(Cb, meanCb, varCb);
float pcr = Gaussian(Cr, meanCr, varCr);
return 2.0f * pcb * pcr;
};
/*************************************************************************
*Function: Skin PDF
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
**************************************************************************/
int f_SkinPDF(unsigned char* srcData, int width, int height, int stride)
{
int ret = 0;
float sum = 0, mean = 0, variance = 0;
unsigned char* pSrc = srcData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
//default setting is computed using special skin data.
//meanCb-varCb:102-196
//meanCr-varCr:143-196
int gray = CLIP3(GetPDF(pSrc[2], pSrc[1], pSrc[0], 102, 196, 143, 196) * 255.0f, 0, 255);
pSrc[0] = pSrc[1] = pSrc[2] = gray;
pSrc += 3;
}
}
return ret;
};
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-4-23
Mail: dongtingyueh@163.com
Description: Skin PDF .
*************************************************************************/
#ifndef __T_SKIN_PDF__
#define __T_SKIN_PDF__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: Skin PDF
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_SkinPDF(unsigned char* srcData, int width, int height, int stride);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_SkinPDF(unsigned char* srcData, int width, int height, int stride);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"Commen.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h"
#include"f_GaussFilter.h"
#include"f_SkinWhite.h"
/*************************************************************************
*Function: SKIN WHITE
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*skinMask: skin mask
*lutData: 32BGRA buffer of lut image.
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_SkinWhite(unsigned char* srcData, int width, int height, int stride, unsigned char* lutData, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(tempData, srcData, sizeof(unsigned char) * length);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(skinPDF, srcData, sizeof(unsigned char) * length);
// ret = f_SkinPDF(skinPDF, width, height, stride);
int maskSmoothRadius = 3;
// ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
ret = f_LUTFilter(tempData, width, height, stride, lutData);
unsigned char* pSrc = srcData;
unsigned char* pLut = tempData;
unsigned char* pSkin = skinPDF;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int r, g, b, a;
b = CLIP3((pSrc[0] * (100 - ratio) + pLut[0] * ratio) / 100, 0, 255);
g = CLIP3((pSrc[1] * (100 - ratio) + pLut[1] * ratio) / 100, 0, 255);
r = CLIP3((pSrc[2] * (100 - ratio) + pLut[2] * ratio) / 100, 0, 255);
a = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
pSrc[0] = CLIP3((b * a + pSrc[0] * (255 - a)) / 255, 0, 255);
pSrc[1] = CLIP3((g * a + pSrc[1] * (255 - a)) / 255, 0, 255);
pSrc[2] = CLIP3((r * a + pSrc[2] * (255 - a)) / 255, 0, 255);
pSrc += 3;
pLut += 3;
pSkin += 3;
}
}
free(tempData);
free(skinPDF);
return ret;
};
/*************************************************************************
*Function: SKIN WHITE USING CURVE
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*belta: intensity of curve enhancement,range[2,10],default:2
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
*Reference: "A Two-Stage Contrast Enhancement Algorithm for Digital Images"
**************************************************************************/
int f_SkinWhiteCurve(unsigned char* srcData, int width, int height, int stride, int belta, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(skinPDF, srcData, sizeof(unsigned char) * length);
ret = f_SkinPDF(skinPDF, width, height, stride);
int maskSmoothRadius = 3;
ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
unsigned char* pSkin = skinPDF;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int r, g, b, a;
//skin white curve
b = CLIP3(log((float)pSrc[0] * (belta - 1) / 255.0f + 1) / log((float)belta) * 255.0f, 0, 255);
g = CLIP3(log((float)pSrc[1] * (belta - 1) / 255.0f + 1) / log((float)belta) * 255.0f, 0, 255);
r = CLIP3(log((float)pSrc[2] * (belta - 1) / 255.0f + 1) / log((float)belta) * 255.0f, 0, 255);
b = CLIP3((b * ratio + pSrc[0] * (100 - ratio)) / 100, 0, 255);
g = CLIP3((g * ratio + pSrc[1] * (100 - ratio)) / 100, 0, 255);
r = CLIP3((r * ratio + pSrc[2] * (100 - ratio)) / 100, 0, 255);
//skin pdf
a = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
pSrc[0] = CLIP3((b * a + pSrc[0] * (255 - a)) / 255, 0, 255);
pSrc[1] = CLIP3((g * a + pSrc[1] * (255 - a)) / 255, 0, 255);
pSrc[2] = CLIP3((r * a + pSrc[2] * (255 - a)) / 255, 0, 255);
pSrc += 3;
pSkin += 3;
}
}
free(skinPDF);
return ret;
}
inline int ModeSmoothLight(int basePixel,int mixPixel)
{
int res = 0;
res = mixPixel > 128 ? ((int)((float)basePixel+((float)mixPixel+(float)mixPixel-255.0f)*((sqrt((float)basePixel/255.0f) )*255.0f-(float)basePixel)/255.0f)):
((int)((float)basePixel+((float)mixPixel+(float)mixPixel-255.0f)*((float)basePixel-(float)basePixel*(float)basePixel/255.0f)/255.0f));
return CLIP3(res, 0, 255);
};
/*************************************************************************
*Function: SKIN WHITE USING SMOOTH LIGHT OF PS
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_SkinWhitePS(unsigned char* srcData, int width, int height, int stride, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(skinPDF, srcData, sizeof(unsigned char) * length);
ret = f_SkinPDF(skinPDF, width, height, stride);
int maskSmoothRadius = 3;
// ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
unsigned char* pSkin = skinPDF;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int r, g, b, a;
//skin white using smoothlight of ps
b = ModeSmoothLight(pSrc[0], 255);
g = ModeSmoothLight(pSrc[1], 255);
r = ModeSmoothLight(pSrc[2], 255);
b = CLIP3((b * ratio + pSrc[0] * (100 - ratio)) / 100, 0, 255);
g = CLIP3((g * ratio + pSrc[1] * (100 - ratio)) / 100, 0, 255);
r = CLIP3((r * ratio + pSrc[2] * (100 - ratio)) / 100, 0, 255);
//skin pdf
a = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
pSrc[0] = CLIP3((b * a + pSrc[0] * (255 - a)) / 255, 0, 255);
pSrc[1] = CLIP3((g * a + pSrc[1] * (255 - a)) / 255, 0, 255);
pSrc[2] = CLIP3((r * a + pSrc[2] * (255 - a)) / 255, 0, 255);
pSrc += 3;
pSkin += 3;
}
}
free(skinPDF);
return ret;
}
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include"f_SmartBlur.h"
#include"TRGB2YCbCr.h"
#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define CLIP3(x, a, b) MIN2(MAX2(a,x), b)
int SmartBlurOneChannel(unsigned char* srcData, int width ,int height, int radius, int threshold)
{
int len = sizeof(unsigned long) * width * height;
int i, j;
int gray = 0;
unsigned char* tempData = (unsigned char*) malloc(sizeof(unsigned char) * height * width);
memcpy(tempData, srcData, sizeof(unsigned char) * height * width);
for(j = 0; j < height; j++ )
{
for(i = 0; i < width; i++)
{
len = i + j * width;
gray = tempData[len];
int low = CLIP3(gray - threshold, 0, 255);
int high = CLIP3(gray + threshold, 0, 255);
int sum = 0;
int count = 0;
for(int n = -radius; n <= radius; n++)
{
for(int m = -radius; m <= radius; m++)
{
int x = CLIP3(i + m, 0, width - 1);
int y = CLIP3(j + n, 0, height - 1);
int pos = x + y * width;
gray = tempData[pos];
if(gray > low && gray < high)
{
sum += gray;
count++;
}
}
}
gray = count == 0 ? srcData[len] : sum / count;//sum / MAX2(count, 1);
srcData[len] = CLIP3(gray, 0, 255);
}
}
free(tempData);
return 0;
};
/*************************************************************************
*Function: Smart Blur
*Params:
*srcData:32BGRA image buffer
*nWidth: width of image
*nHeight: height of image
*nStride: Stride of image
*radius: radius of filter, [0,+]
*threshold: threshold of pixels to count,[0,255]
*Return: 0-OK,other failed
**************************************************************************/
int f_SmartBlur(unsigned char* srcData, int nWidth, int nHeight, int nStride, int radius, int threshold)
{
int ret = 0;
if (srcData == NULL)
{
return ret;
}
if(radius == 0 || threshold == 0)
return ret;
unsigned char* yData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
unsigned char* cbData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
unsigned char* crData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
unsigned char* pSrc = srcData;
int Y, CB, CR;
unsigned char* pY = yData;
unsigned char* pCb = cbData;
unsigned char* pCr = crData;
for(int j = 0; j < nHeight; j++)
{
for(int i = 0; i < nWidth; i++)
{
RGBToYCbCr(pSrc[2],pSrc[1],pSrc[0],&Y,&CB,&CR);
*pY = Y;
*pCb = CB;
*pCr = CR;
pY++;
pCb++;
pCr++;
pSrc += 4;
}
}
SmartBlurOneChannel(yData, nWidth, nHeight, radius, threshold);
pSrc = srcData;
pY = yData;
pCb = cbData;
pCr = crData;
int R, G, B;
for(int j = 0; j < nHeight; j++)
{
for(int i = 0; i < nWidth; i++)
{
YCbCrToRGB(*pY, *pCb, *pCr, &R, &G, &B);
pSrc[0] = B;
pSrc[1] = G;
pSrc[2] = R;
pY++;
pCb++;
pCr++;
pSrc += 4;
}
}
free(yData);
free(cbData);
free(crData);
return ret;
}
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-4-23
Mail: dongtingyueh@163.com
Description: Smart Blur .
Refference: None
*************************************************************************/
#ifndef __T_SMART_BLUR__
#define __T_SMART_BLUR__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: Smart Blur
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*radius: radius of filter, [0,+]
*threshold: threshold of pixels to count,[0,255]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_SmartBlur(unsigned char* srcData, int width, int height, int stride, int radius, int threshold);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_SmartBlur(unsigned char* srcData, int width, int height, int stride, int radius, int threshold);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"f_SoftSkin_ChannelMethod.h"
#include"f_GaussFilter.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h" //3.10
//#include"disabled/f_SkinDetect.h"//3.9
#include"f_Commen_MixLayer.h"
/*************************************************************************
*Function: SOFT SKIN CHANNEL METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*lightMap: light curve map data with format BGRA32
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_Softskin_ChannelMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int ratio)
{
int ret = 0;
unsigned char* greenData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* gaussData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* curveData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* skinData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* pSrc = srcData;
unsigned char* pGreen = greenData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pGreen[0] = pSrc[0];
pGreen[1] = pSrc[0];
pGreen[2] = pSrc[0];
pSrc += 4;
pGreen += 4;
}
}
memcpy(gaussData, greenData, sizeof(unsigned char) * height * stride);
memcpy(curveData, srcData, sizeof(unsigned char) * height * stride);
ret = f_LUTFilter(curveData, width, height, stride, lightMap);
float hpRadius = 10.0f * width * height / (594 * 677);
ret = f_FastGaussFilter(gaussData, width, height, stride,hpRadius);
pSrc = srcData;
pGreen = greenData;
unsigned char* pCurve = curveData;
unsigned char* pGauss = gaussData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int t;
t = CLIP3(pGauss[0] - pGreen[0] + 128, 0, 255);
t = ModeSuperposition(t, t);
t = ModeSuperposition(t, t);
t = t * 220 / 255;
pGreen[0] = CLIP3((pCurve[0] * t + (255 - t) * pSrc[0]) / 255, 0, 255);
pGreen[1] = CLIP3((pCurve[1] * t + (255 - t) * pSrc[1]) / 255, 0, 255);
pGreen[2] = CLIP3((pCurve[2] * t + (255 - t) * pSrc[2]) / 255, 0, 255);
pGreen += 4;
pGauss += 4;
pSrc += 4;
pCurve += 4;
}
}
memcpy(skinData, greenData, sizeof(unsigned char) * height * stride);
int maskSmoothRadius = 3 * width * height / (594 * 677);
ret = f_SkinPDF(skinData, width, height, stride);
ret = f_FastGaussFilter(skinData, width, height, stride, maskSmoothRadius);
pGauss = skinData;
pSrc = srcData;
pGreen = greenData;
int k = ratio * 128 / 100;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int mask = (pGauss[0] + pGauss[1] + pGauss[2]) / 3;
int tb = CLIP3((pSrc[0] * (255 - mask) + pGreen[0] * mask) / 255, 0, 255);
int tg = CLIP3((pSrc[1] * (255 - mask) + pGreen[1] * mask) / 255, 0, 255);
int tr = CLIP3((pSrc[2] * (255 - mask) + pGreen[2] * mask) / 255, 0, 255);
pSrc[0] = CLIP3((pSrc[0] * (128 - k) + tb * k) >> 7, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (128 - k) + tg * k) >> 7, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (128 - k) + tr * k) >> 7, 0, 255);
pSrc += 4;
pGauss += 4;
pGreen += 4;
}
}
free(gaussData);
free(greenData);
free(curveData);
free(skinData);
return ret;
};
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Soft skin .
*************************************************************************/
#ifndef __T_SOFT_SKIN_CHANNEL_METHOD__
#define __T_SOFT_SKIN_CHANNEL_METHOD__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SOFT SKIN CHANNEL METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*lightMap: light curve map data with format BGRA32
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_Softskin_ChannelMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int ratio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_Softskin_ChannelMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int ratio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"f_GaussFilter.h"
#include"f_SkinPDF.h" //3.10
//#include"disabled/f_SkinDetect.h"//3.9
#include"f_Commen_MixLayer.h"
#include"f_SoftSkin_DetailsAddingMethod.h"
#include"f_SmartBlur.h"
#include"f_SurfaceBlur.h"
/*************************************************************************
*Function: SOFT SKIN DETAILSADDED METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*K: intensity of details controled, range [0,300]
*Return: 0-OK,other failed
**************************************************************************/
int f_Softskin_DetailsAddingMethod(unsigned char* srcData, int width, int height, int stride, int ratio, float K)
{
int ret = 0;
int len = sizeof(unsigned char) * height * stride;
unsigned char*coarseSmoothData = (unsigned char*)malloc(len);
unsigned char*fineSmoothData = (unsigned char*)malloc(len);
memcpy(coarseSmoothData, srcData, len);
memcpy(fineSmoothData, srcData, len);
int std_fine = 5;
int std_coarse = 10;
f_SmartBlur(fineSmoothData, width, height, stride, std_fine, 30);
f_SmartBlur(coarseSmoothData, width, height, stride, std_coarse, 30);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * len);
memcpy(skinPDF, coarseSmoothData, sizeof(unsigned char) * len);
ret = f_SkinPDF(skinPDF, width, height, stride);
float maskSmoothRadius = 3;
ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
unsigned char* pCoarse = coarseSmoothData;
unsigned char* pFine = fineSmoothData;
unsigned char* pSkin = skinPDF;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int alpha = *pSkin * ratio / 100;
int detailsFine = pSrc[0] - pFine[0];
int detailsCoarse = pFine[0] - pCoarse[0];
float K0 = alpha / 255.0f;
pSrc[0] = (unsigned char)CLIP3(pCoarse[0] + (255 - alpha) * detailsCoarse / 255 + (1.0f - K0 * K) * detailsFine, 0, 255);
detailsFine = pSrc[1] - pFine[1];
detailsCoarse = pFine[1] - pCoarse[1];
pSrc[1] = (unsigned char)CLIP3(pCoarse[1] + (255 - alpha) * detailsCoarse / 255 + (1.0f - K0 * K) * detailsFine, 0, 255);
detailsFine = pSrc[2] - pFine[2];
detailsCoarse = pFine[2] - pCoarse[2];
pSrc[2] = (unsigned char)CLIP3(pCoarse[2] + (255 - alpha) * detailsCoarse / 255 + (1.0f - K0 * K) * detailsFine, 0, 255);
pSrc += 4;
pCoarse += 4;
pFine += 4;
pSkin += 4;
}
}
free(skinPDF);
free(coarseSmoothData);
free(fineSmoothData);
return ret;
};
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Soft skin .
*************************************************************************/
#ifndef __T_SOFT_SKIN_HP_METHOD__
#define __T_SOFT_SKIN_HP_METHOD__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SOFT SKIN DETAILS ADDING METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*ratio: Intensity of softskin,range [0,100]
*K: details params, range [0,500]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_Softskin_DetailsAddingMethod(unsigned char* srcData, int width, int height, int stride, int ratio, float K);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_Softskin_DetailsAddingMethod(unsigned char* srcData, int width, int height, int stride, int ratio, float K);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"f_SoftSkin_HPMethod.h"
#include"f_GaussFilter.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h" //3.10
//#include"disabled/f_SkinDetect.h"//3.9
#include"f_SmartBlur.h"
#include"f_SurfaceBlur.h"
#include"f_Commen_MixLayer.h"
/*************************************************************************
*Function: SOFT SKIN HP METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*textureRatio: intensity of details controled, range [0,100]
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_Softskin_HP(unsigned char* srcData, int width, int height, int stride, int textureRatio, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* smoothData = (unsigned char*)malloc(sizeof(unsigned char) * length);
unsigned char* hpData = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(smoothData, srcData, sizeof(unsigned char) * length);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
int smoothRadius = 8;
int smoothThreshold = 38;
int maskSmoothRadius = 3;
ret = f_SurfaceBlur(smoothData, width, height, stride, smoothRadius, smoothThreshold);
memcpy(skinPDF, smoothData, sizeof(unsigned char) * length);
ret = f_SkinPDF(skinPDF, width, height, stride);
ret = f_FastGaussFilter(skinPDF, width, height, stride, maskSmoothRadius);
unsigned char* pSrc = srcData;
unsigned char* pSkin = skinPDF;
unsigned char* pSmooth = smoothData;
unsigned char* pHP = hpData;
int k = ratio * 128 / 100;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pHP[0] = CLIP3(pSmooth[0] - pSrc[0] + 128, 0, 255);
pHP[1] = CLIP3(pSmooth[1] - pSrc[1] + 128, 0, 255);
pHP[2] = CLIP3(pSmooth[2] - pSrc[2] + 128, 0, 255);
pHP += 4;
pSmooth += 4;
pSrc += 4;
}
}
float hpRadius = 3.5f * textureRatio / 100.0f;
ret = f_FastGaussFilter(hpData, width, height, stride, hpRadius);
pSmooth = smoothData;
pHP = hpData;
pSrc = srcData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int hpb = pHP[0];
int hpg = pHP[1];
int hpr = pHP[2];
hpb = ModeLinearLight(pSrc[0], hpb);
hpg = ModeLinearLight(pSrc[1], hpg);
hpr = ModeLinearLight(pSrc[2], hpr);
int mask = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
hpb = CLIP3((hpb * mask + pSmooth[0] * (255 - mask)) / 255, 0, 255);
hpg = CLIP3((hpg * mask + pSmooth[1] * (255 - mask)) / 255, 0, 255);
hpr = CLIP3((hpr * mask + pSmooth[2] * (255 - mask)) / 255, 0, 255);
pSrc[0] = CLIP3((hpb * k + pSrc[0] * (128 - k)) >> 7, 0, 255);
pSrc[1] = CLIP3((hpg * k + pSrc[1] * (128 - k)) >> 7, 0, 255);
pSrc[2] = CLIP3((hpr * k + pSrc[2] * (128 - k)) >> 7, 0, 255);
pSrc += 4;
pHP += 4;
pSmooth += 4;
pSkin += 4;
}
}
free(skinPDF);
free(smoothData);
free(hpData);
return ret = 0;
};
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Soft skin .
*************************************************************************/
#ifndef __T_SOFT_SKIN_HP_METHOD__
#define __T_SOFT_SKIN_HP_METHOD__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SOFT SKIN HP METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*textureRatio: intensity of details controled, range [0,100]
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_Softskin_HP(unsigned char* srcData, int width, int height, int stride, int textureRatio, int ratio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_Softskin_HP(unsigned char* srcData, int width, int height, int stride, int textureRatio, int ratio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include"Commen.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"f_SoftSkin_ChannelMethod.h"
#include"f_GaussFilter.h"
#include"f_LUTFilter.h"
#include"f_SkinPDF.h" //3.10
//#include"disabled/f_SkinDetect.h"//3.9
#include"f_SmartBlur.h"
#include"f_SoftSkin_HPMethod.h"
#include"f_SurfaceBlur.h"
#include"f_Commen_MixLayer.h"
#include"f_SoftSkin_MixMethod.h"
int Softskin_A(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int ratio)
{
int ret = 0;
unsigned char* greenData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* gaussData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* curveData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* skinData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* smoothData = (unsigned char*)malloc(sizeof(unsigned char) * stride * height);
unsigned char* pSrc = srcData;
unsigned char* pGreen = greenData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
pGreen[0] = pSrc[0];
pGreen[1] = pSrc[0];
pGreen[2] = pSrc[0];
pSrc += 4;
pGreen += 4;
}
}
memcpy(gaussData, greenData, sizeof(unsigned char) * height * stride);
memcpy(curveData, srcData, sizeof(unsigned char) * height * stride);
ret = f_LUTFilter(curveData, width, height, stride, lightMap);
float hpRadius = 10.0f * width * height / (594 * 677);
ret = f_FastGaussFilter(gaussData, width, height, stride,hpRadius);
pSrc = srcData;
pGreen = greenData;
unsigned char* pCurve = curveData;
unsigned char* pGauss = gaussData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int t;
t = CLIP3(pGauss[0] - pGreen[0] + 128, 0, 255);
t = ModeSuperposition(t, t);
t = ModeSuperposition(t, t);
t = t * 200 / 255;
pGreen[0] = CLIP3((pCurve[0] * t + (255 - t) * pSrc[0]) / 255, 0, 255);
pGreen[1] = CLIP3((pCurve[1] * t + (255 - t) * pSrc[1]) / 255, 0, 255);
pGreen[2] = CLIP3((pCurve[2] * t + (255 - t) * pSrc[2]) / 255, 0, 255);
pGreen += 4;
pGauss += 4;
pSrc += 4;
pCurve += 4;
}
}
int k = ratio * 128 / 100;
memcpy(smoothData, greenData, sizeof(unsigned char) * stride * height);
int smoothRadius = 6;
int smoothThreshold = 38;
ret = f_SmartBlur(smoothData, width, height, stride, smoothRadius, smoothThreshold);
memcpy(skinData, smoothData, sizeof(unsigned char) * height * stride);
int maskSmoothRadius = 3;
ret = f_SkinPDF(skinData, width, height, stride);
ret = f_FastGaussFilter(skinData, width, height, stride, maskSmoothRadius);
pGauss = skinData;
pSrc = srcData;
pGreen = greenData;
unsigned char* pSmooth = smoothData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int mask = (pGauss[0] + pGauss[1] + pGauss[2]) / 3;
int tb = CLIP3((pSrc[0] * (255 - mask) + pGreen[0] * mask) / 255, 0, 255);
int tg = CLIP3((pSrc[1] * (255 - mask) + pGreen[1] * mask) / 255, 0, 255);
int tr = CLIP3((pSrc[2] * (255 - mask) + pGreen[2] * mask) / 255, 0, 255);
tb = CLIP3((tb * (255 - mask) + pSmooth[0] * mask) / 255, 0, 255);
tg = CLIP3((tg * (255 - mask) + pSmooth[1] * mask) / 255, 0, 255);
tr = CLIP3((tr * (255 - mask) + pSmooth[2] * mask) / 255, 0, 255);
pSrc[0] = CLIP3((pSrc[0] * (128 - k) + tb * k) >> 7, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (128 - k) + tg * k) >> 7, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (128 - k) + tr * k) >> 7, 0, 255);
pSrc += 4;
pGauss += 4;
pGreen += 4;
pSmooth += 4;
}
}
free(gaussData);
free(greenData);
free(curveData);
free(skinData);
free(smoothData);
return ret;
}
//
//
/*************************************************************************
*Function: SOFT SKIN MIXED METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*lightMap: light curve map data with format BGRA32
*textureRatio: intensity of details controled, range [0,100]
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
int f_Softskin_MixMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int textureRatio, int ratio)
{
int ret = 0;
int length = height * stride;
unsigned char* smoothData = (unsigned char*)malloc(sizeof(unsigned char) * length);
unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * length);
unsigned char* hpData = (unsigned char*)malloc(sizeof(unsigned char) * length);
memcpy(smoothData, srcData, sizeof(unsigned char) * length);
memcpy(tempData, srcData, sizeof(unsigned char) * length);
unsigned char* skinPDF = (unsigned char*)malloc(sizeof(unsigned char) * length);
int smoothRadius = 8;
int smoothThreshold = 38;
int maskSmoothRadius = 3;
ret = Softskin_A(smoothData, width, height, stride, lightMap, 95);
memcpy(skinPDF, smoothData, sizeof(unsigned char) * length);
ret = f_SkinPDF(skinPDF, width, height, stride);
unsigned char* pSrc = srcData;
unsigned char* pSkin = skinPDF;
unsigned char* pSmooth = smoothData;
unsigned char* pHP = hpData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int mask = 128 - textureRatio * 128 / 100;
pSrc[0] = CLIP3((pSrc[0] * (128 - mask) + pSmooth[0] * mask) >> 7, 0, 255);
pSrc[1] = CLIP3((pSrc[1] * (128 - mask) + pSmooth[1] * mask) >> 7, 0, 255);
pSrc[2] = CLIP3((pSrc[2] * (128 - mask) + pSmooth[2] * mask) >> 7, 0, 255);
pHP[0] = CLIP3(pSmooth[0] - pSrc[0] + 128, 0, 255);
pHP[1] = CLIP3(pSmooth[1] - pSrc[1] + 128, 0, 255);
pHP[2] = CLIP3(pSmooth[2] - pSrc[2] + 128, 0, 255);
pHP += 4;
pSmooth += 4;
pSrc += 4;
pSkin += 4;
}
}
float hpRadius = 3.1;
ret = f_FastGaussFilter(hpData, width, height, stride, hpRadius);
pSrc = srcData;
pSkin = skinPDF;
pSmooth = smoothData;
pHP = hpData;
int k = ratio * 128 / 100;
unsigned char* pTemp = tempData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
int hpb = pHP[0];
int hpg = pHP[1];
int hpr = pHP[2];
hpb = ModeLinearLight(pSrc[0], hpb);
hpg = ModeLinearLight(pSrc[1], hpg);
hpr = ModeLinearLight(pSrc[2], hpr);
int mask = (pSkin[0] + pSkin[1] + pSkin[2]) / 3;
hpb = CLIP3((hpb * mask + pSmooth[0] * (255 - mask)) / 255, 0, 255);
hpg = CLIP3((hpg * mask + pSmooth[1] * (255 - mask)) / 255, 0, 255);
hpr = CLIP3((hpr * mask + pSmooth[2] * (255 - mask)) / 255, 0, 255);
pSrc[0] = CLIP3((hpb * k + pTemp[0] * (128 - k)) >> 7, 0, 255);
pSrc[1] = CLIP3((hpg * k + pTemp[1] * (128 - k)) >> 7, 0, 255);
pSrc[2] = CLIP3((hpr * k + pTemp[2] * (128 - k)) >> 7, 0, 255);
pSrc += 4;
pHP += 4;
pSmooth += 4;
pSkin += 4;
pTemp += 4;
}
}
free(skinPDF);
free(smoothData);
free(hpData);
free(tempData);
return ret;
};
\ No newline at end of file
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-11-23
Mail: dongtingyueh@163.com
Description: Soft skin .
*************************************************************************/
#ifndef __T_SOFT_SKIN_MIX_METHOD__
#define __T_SOFT_SKIN_MIX_METHOD__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*************************************************************************
*Function: SOFT SKIN MIXED METHOD
*Params:
*srcData:32BGRA image buffer
*width: width of image
*height: height of image
*stride: Stride of image
*lightMap: light curve map data with format BGRA32
*textureRatio: intensity of details controled, range [0,100]
*ratio: Intensity of softskin,range [0,100]
*Return: 0-OK,other failed
**************************************************************************/
EXPORT int f_Softskin_MixMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int textureRatio, int ratio);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_Softskin_MixMethod(unsigned char* srcData, int width, int height, int stride, unsigned char* lightMap, int textureRatio, int ratio);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include"f_SurfaceBlur.h"
#include"TRGB2YCbCr.h"
#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define CLIP3(x, a, b) MIN2(MAX2(a,x), b)
static int SurfaceBlurOneChannel(unsigned char* srcData, int width, int height, float* map, int radius)
{
int ret = 0;
int i, j, n, m, len;
len = sizeof(unsigned char) * width * height;
unsigned char* tempData = (unsigned char*)malloc(len);
int* tmap = (int*)malloc(sizeof(int) * height);
if(tempData == NULL || tmap == NULL)
{
ret = 1;
return ret;
}
if(NULL == tempData || NULL == tmap)
return 1;
for(i = 0; i < height; i ++)
{
tmap[i] = i * width;
}
memcpy(tempData, srcData, len);
int kx, ky;
len = (radius << 1) + 1;
int gray = 0;
float sum, sum_a;
int pos, pos_a;
unsigned char val;
for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
pos = i + tmap[j];
val = tempData[pos];
sum = 0;
sum_a = 0;
for(n = -radius; n <= radius; n++)
{
ky = CLIP3(j + n, 0, height - 1);
pos_a = tmap[ky];
for(m = -radius; m <= radius; m++)
{
kx = CLIP3(i + m, 0, width - 1);
gray = tempData[kx + pos_a];
sum_a += map[gray - val];
sum += gray * map[gray - val];
}
}
gray = sum_a == 0 ? gray : sum / sum_a;//(int)(sum / MAX2(sum_a, 0.1));
srcData[pos] = gray;//CLIP3(gray, 0 , 255);
}
}
free(tempData);
free(tmap);
return ret;
};
/*****************************************************
*Function: Surface blur
*Params:
*srcData-32BGRA image data
*width-width of image
*height-height of image
*stride-Stride of image
*radius-radius of surface blur, [0,100]
*threshold-Threshold of surface blur, [0,255]
*Return: 0-OK, or failed.
******************************************************/
int f_SurfaceBlur(unsigned char* srcData, int width, int height, int stride, int radius, int threshold)
{
if (srcData == NULL || radius == 0 || threshold == 0)
{
return 0;
}
unsigned char* yData = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
unsigned char* cbData = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
unsigned char* crData = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
unsigned char* pSrc = srcData;
int Y, CB, CR;
unsigned char* pY = yData;
unsigned char* pCb = cbData;
unsigned char* pCr = crData;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
RGBToYCbCr(pSrc[2],pSrc[1],pSrc[0],&Y,&CB,&CR);
*pY = Y;
*pCb = CB;
*pCr = CR;
pY++;
pCb++;
pCr++;
pSrc += 3;
}
}
float matrixItems[511];//255*2+1
float* items = &matrixItems[255];
float fv = threshold * 2.5f;
for(int i = 0; i < 256; i++)
{
items[-i] = items[i] = MAX2(1 - i / fv, 0);
}
SurfaceBlurOneChannel(yData, width, height, items, radius);
SurfaceBlurOneChannel(cbData, width, height, items, radius);
SurfaceBlurOneChannel(crData, width, height, items, radius);
pSrc = srcData;
pY = yData;
pCb = cbData;
pCr = crData;
int R, G, B;
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
YCbCrToRGB(*pY, *pCb, *pCr, &R, &G, &B);
pSrc[0] = B;
pSrc[1] = G;
pSrc[2] = R;
pY++;
pCb++;
pCr++;
pSrc += 3;
}
}
free(yData);
free(cbData);
free(crData);
return 0;
}
/*************************************************************************
Copyright: HZ.
Author: Hu Yaowu
Date: 2018-4-23
Mail: dongtingyueh@163.com
Description: Surface blur .
*************************************************************************/
#ifndef __T_SURFACE_BLUR__
#define __T_SURFACE_BLUR__
#ifdef _MSC_VER
#ifdef __cplusplus
#define EXPORT extern "C" _declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
/*****************************************************
*Function: Surface blur
*Params:
*srcData-32BGRA image data
*width-width of image
*height-height of image
*stride-Stride of image
*radius-radius of surface blur, [0,100]
*threshold-Threshold of surface blur, [0,255]
*Return: 0-OK, or failed.
******************************************************/
EXPORT int f_SurfaceBlur(unsigned char* srcData, int width, int height, int stride, int radius, int threshold);
#else
#ifdef __cplusplus
extern "C" {
#endif
int f_SurfaceBlur(unsigned char* srcData, int width, int height, int stride, int radius, int threshold);
#ifdef __cplusplus
}
#endif
#endif
#endif
#include <tuple>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iterator>
using namespace cv;
using namespace cv::dnn;
using namespace std;
/**
* @brief Get the Face Box object 人脸定位
*
* @param net 人脸检测网络
* @param frame 检测图像
* @param conf_threshold 阈值
* @return tuple<Mat, vector<vector<int>>> 元组容器,可返回多个值
*/
tuple<Mat, vector<vector<int>>> getFaceBox(Net net, Mat &frame, double conf_threshold)
{
//图像复制
Mat frameOpenCVDNN = frame.clone();
int frameHeight = frameOpenCVDNN.rows;
int frameWidth = frameOpenCVDNN.cols;
//缩放尺寸
double inScaleFactor = 1.0;
//检测图大小
Size size = Size(300, 300);
// std::vector<int> meanVal = {104, 117, 123};
Scalar meanVal = Scalar(104, 117, 123);
cv::Mat inputBlob;
inputBlob = cv::dnn::blobFromImage(frameOpenCVDNN, inScaleFactor, size, meanVal, true, false);
net.setInput(inputBlob, "data");
//四维矩阵输出
cv::Mat detection = net.forward("detection_out");
//提取结果信息
cv::Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
vector<vector<int>> bboxes;
for (int i = 0; i < detectionMat.rows; i++)
{
//预测概率
float confidence = detectionMat.at<float>(i, 2);
if (confidence > conf_threshold)
{
//左上角点,坐标被归一化
int x1 = static_cast<int>(detectionMat.at<float>(i, 3) * frameWidth);
int y1 = static_cast<int>(detectionMat.at<float>(i, 4) * frameHeight);
//右下角角点,坐标被归一化
int x2 = static_cast<int>(detectionMat.at<float>(i, 5) * frameWidth);
int y2 = static_cast<int>(detectionMat.at<float>(i, 6) * frameHeight);
vector<int> box = { x1, y1, x2, y2 };
//人脸坐标
bboxes.push_back(box);
//图像框选
cv::rectangle(frameOpenCVDNN, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2, 4);
}
}
return make_tuple(frameOpenCVDNN, bboxes);
}
#include <fstream>
#include "Poco/StringTokenizer.h"
#include "Poco/Stopwatch.h"
Scalar MODEL_MEAN_VALUES = Scalar(104, 117, 123);
int main5(void) {
string modelBaseDir = "/Users/edz/Downloads/";
string genderProto = modelBaseDir+"genderModel/gender.prototxt";
string genderModel = modelBaseDir+"genderModel/gender.caffemodel";
//性别标签
vector<string> genderList = {"Male", "Female"};
//导入网络
Net genderNet = cv::dnn::readNet(genderProto, genderModel);
ifstream ifs("/Users/edz/Downloads/wiki_crop/gender.txt");
if(!ifs.is_open()){
cout << "文件未打开成功" << endl;
return 0;
}
Poco::Stopwatch stopwatch;
stopwatch.start();
vector<int> pV;
vector<string> nV;
string line;
int count = 0;
while(getline(ifs,line)){
Poco::StringTokenizer stringTokenizer(line," ");
string fileName = stringTokenizer[0];
if(fileName!="61/22156261_1992-10-16_2011.jpg"){
continue;
}
int gender = stoi(stringTokenizer[1]);
Mat face;
face = imread("/Users/edz/Downloads/wiki_crop/"+fileName);
//性别检测
Mat blob;
blob = blobFromImage(face, 1, Size(224, 224), MODEL_MEAN_VALUES, true);
genderNet.setInput(blob);
// string gender_preds; 获取前向传播softmax结果
vector<float> genderPreds = genderNet.forward();
// find max element index max_element用于找寻最大值
// distance function does the argmax() work in C++ distance返回最大值和第一个值下标的距离
int max_index_gender = std::distance(genderPreds.begin(),
max_element(genderPreds.begin(), genderPreds.end()));
//获得检测结果
pV.push_back(max_index_gender==gender);
if(max_index_gender!=gender){
nV.push_back("/Users/edz/Downloads/wiki_crop/"+fileName);
}
// string gender = genderList[max_index_gender];
// cout << "Gender: " << gender << endl;
++count;
cout << int(stopwatch.elapsed()/1000) << endl;
imshow("bug",face);
waitKey(0);
if(count==1){
break;
}
}
int nC = 0;
for(auto it:pV){
if(it==0){
++nC;
}
}
for(auto it:nV){
cout << it << endl;
}
cout << "正确率:" << (pV.size()-nC)*1.0/pV.size() << endl;
cout << "总耗时:" << int(stopwatch.elapsed()/1000) << endl;
ifs.close();
return 0;
}
int main22(void) {
string modelBaseDir = "/Users/edz/Downloads/";
string genderProto = modelBaseDir+"genderModel/gender.prototxt";
string genderModel = modelBaseDir+"genderModel/gender.caffemodel";
//性别标签
vector<string> genderList = {"Male", "Female"};
//导入网络
Net genderNet = cv::dnn::readNet(genderProto, genderModel);
ifstream ifs("/Users/edz/Downloads/wiki_crop/gender.txt");
if(!ifs.is_open()){
cout << "文件未打开成功" << endl;
return 0;
}
Poco::Stopwatch stopwatch;
stopwatch.start();
vector<int> pV;
vector<string> nV;
string line;
int totalCount = 1000;
int count = 0;
while(getline(ifs,line)){
Poco::StringTokenizer stringTokenizer(line," ");
string fileName = stringTokenizer[0];
int gender = stoi(stringTokenizer[1]);
Mat face;
face = imread("/Users/edz/Downloads/wiki_crop/"+fileName);
cout << "总耗时1:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
//性别检测
Mat blob;
blob = blobFromImage(face, 1, Size(224, 224), MODEL_MEAN_VALUES, true);
cout << "总耗时2:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
genderNet.setInput(blob);
cout << "总耗时3:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
// string gender_preds; 获取前向传播softmax结果
vector<float> genderPreds = genderNet.forward();
cout << "总耗时4:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
// find max element index max_element用于找寻最大值
// distance function does the argmax() work in C++ distance返回最大值和第一个值下标的距离
int max_index_gender = std::distance(genderPreds.begin(),
max_element(genderPreds.begin(), genderPreds.end()));
cout << "总耗时5:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
//获得检测结果
pV.push_back(max_index_gender==gender);
cout << "总耗时6:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
if(max_index_gender!=gender){
nV.push_back("/Users/edz/Downloads/wiki_crop/"+fileName);
}
// string gender = genderList[max_index_gender];
// cout << "Gender: " << gender << endl;
++count;
cout << "已完成:" << count*1.0*100/totalCount << "%" << endl;
if(count==totalCount){
break;
}
}
int nC = 0;
for(auto it:pV){
if(it==0){
++nC;
}
}
for(auto it:nV){
cout << it << endl;
}
cout << "正样本数:" << count-nC << endl;
cout << "负样本数:" << nC << endl;
cout << "总样本数:" << count << endl;
cout << "正确率:" << (pV.size()-nC)*1.0*100/pV.size() << "%" << endl;
cout << "总耗时:" << int(stopwatch.elapsed()/1000) << "ms" << endl;
cout << "单次平均耗时:" << int(stopwatch.elapsed()/1000/count) << "ms" << endl;
ifs.close();
return 0;
}
int main2(void) {
//人脸模型
string modelBaseDir = "/Users/edz/Downloads/";
string faceProto = modelBaseDir+"2opencv_dlib_face_detection/model/opencv_face_detector.pbtxt";
string faceModel = modelBaseDir+"2opencv_dlib_face_detection/model/opencv_face_detector_uint8.pb";
//年龄模型
// string ageProto = modelBaseDir+"1age_gender/age_deploy.prototxt";
// string ageModel = modelBaseDir+"1age_gender/age_net.caffemodel";
//性别模型
// string genderProto = modelBaseDir+"1age_gender/gender_deploy.prototxt";
// string genderModel = modelBaseDir+"1age_gender/gender_net.caffemodel";
string genderProto = modelBaseDir+"genderModel/gender.prototxt";
string genderModel = modelBaseDir+"genderModel/gender.caffemodel";
//均值
Scalar MODEL_MEAN_VALUES = Scalar(104, 117, 123);
//年龄段标签
vector<string> ageList = {"(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)",
"(38-43)", "(48-53)", "(60-100)"};
//性别标签
vector<string> genderList = {"Female", "Male"};
//导入网络
// Net ageNet = cv::dnn::readNet(ageProto, ageModel);
Net genderNet = cv::dnn::readNet(genderProto, genderModel);
Net faceNet = cv::dnn::readNetFromTensorflow(faceModel, faceProto);
//打开摄像头
VideoCapture cap;
cap.open(0);
if (cap.isOpened()) {
cout << "camera is opened!" << endl;
} else {
return 0;
}
int padding = 20;
while (waitKey(1) < 0) {
// read frame 读图
Mat frame;
cap.read(frame);
if (frame.empty()) {
waitKey();
break;
}
cout << frame.type() << endl;
// frame = imread("./images/couple1.jpg");
//人脸坐标
vector<vector<int>> bboxes;
//人脸检测结果图
Mat frameFace;
//人脸定位
//tie()函数解包frameFace和bboxes
tie(frameFace, bboxes) = getFaceBox(faceNet, frame, 0.7);
//人脸判断
if (bboxes.size() == 0) {
cout << "No face detected, checking next frame." << endl;
continue;
}
cout << "face detected, checking next frame." << endl;
//逐个提取人脸检测
for (auto it = begin(bboxes); it != end(bboxes); ++it) {
//框选人脸
Rect rec(it->at(0) - padding, it->at(1) - padding, it->at(2) - it->at(0) + 2 * padding,
it->at(3) - it->at(1) + 2 * padding);
//避免人脸框选超过图像边缘
rec.width = ((rec.x + rec.width) > frame.cols) ? (frame.cols - rec.x - 1) : rec.width;
rec.height = ((rec.y + rec.height) > frame.rows) ? (frame.rows - rec.y - 1) : rec.height;
// take the ROI of box on the frame,原图中提取人脸
Mat face = frame(rec);
//性别检测
Mat blob;
blob = blobFromImage(face, 1, Size(224, 224), MODEL_MEAN_VALUES, true);
cout << "genderNet start." << endl;
cout << blob.size << endl;
cout << blob.rows << endl;
cout << blob.cols << endl;
cout << blob.dims << endl;
genderNet.setInput(blob);
// string gender_preds; 获取前向传播softmax结果
vector<float> genderPreds = genderNet.forward();
cout << "genderNet end." << endl;
// find max element index max_element用于找寻最大值
// distance function does the argmax() work in C++ distance返回最大值和第一个值下标的距离
int max_index_gender = std::distance(genderPreds.begin(),
max_element(genderPreds.begin(), genderPreds.end()));
//获得检测结果
string gender = genderList[max_index_gender];
cout << "Gender: " << gender << endl;
//年龄识别
// blob = blobFromImage(face, 1, Size(227, 227), MODEL_MEAN_VALUES, false);
// ageNet.setInput(blob);
// vector<float> agePreds = ageNet.forward();
// // finding maximum indicd in the age_preds vector 找到年龄预测最大下表
// int max_indice_age = std::distance(agePreds.begin(), max_element(agePreds.begin(), agePreds.end()));
// string age = ageList[max_indice_age];
// cout << "Age: " << age << endl;
// label 输出标签
// string label = gender + ", " + age;
string label = gender;
//在人脸定位图上显示结果
cv::putText(frameFace, label, Point(it->at(0), it->at(1) - 15), cv::FONT_HERSHEY_SIMPLEX, 0.9,
Scalar(0, 255, 255), 2, cv::LINE_AA);
}
//保存结果
imshow("Frame", frameFace);
// imwrite("out.jpg", frameFace);
}
}
int main3(void) {
//人脸模型
string modelBaseDir = "/Users/edz/Downloads/";
string faceProto = modelBaseDir+"2opencv_dlib_face_detection/model/opencv_face_detector.pbtxt";
string faceModel = modelBaseDir+"2opencv_dlib_face_detection/model/opencv_face_detector_uint8.pb";
//年龄模型
string ageProto = modelBaseDir+"1age_gender/age_deploy.prototxt";
string ageModel = modelBaseDir+"1age_gender/age_net.caffemodel";
//性别模型
// string genderProto = modelBaseDir+"1age_gender/gender_deploy.prototxt";
// string genderModel = modelBaseDir+"1age_gender/gender_net.caffemodel";
string genderProto = modelBaseDir+"genderModel/gender.prototxt";
string genderModel = modelBaseDir+"genderModel/gender.caffemodel";
//均值
Scalar MODEL_MEAN_VALUES = Scalar(78.4263377603, 87.7689143744, 114.895847746);
//年龄段标签
vector<string> ageList = {"(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)",
"(38-43)", "(48-53)", "(60-100)"};
//性别标签
vector<string> genderList = {"Male", "Female"};
//导入网络
Net ageNet = cv::dnn::readNet(ageProto, ageModel);
Net genderNet = cv::dnn::readNet(genderProto, genderModel);
Net faceNet = cv::dnn::readNetFromTensorflow(faceModel, faceProto);
//打开摄像头
VideoCapture cap;
cap.open(0);
if (cap.isOpened()) {
cout << "camera is opened!" << endl;
} else {
return 0;
}
int padding = 20;
while (waitKey(1) < 0) {
// read frame 读图
Mat frame;
cap.read(frame);
if (frame.empty()) {
waitKey();
break;
}
// frame = imread("./images/couple1.jpg");
//人脸坐标
vector<vector<int>> bboxes;
//人脸检测结果图
Mat frameFace;
//人脸定位
//tie()函数解包frameFace和bboxes
tie(frameFace, bboxes) = getFaceBox(faceNet, frame, 0.7);
//人脸判断
if (bboxes.size() == 0) {
cout << "No face detected, checking next frame." << endl;
continue;
}
//逐个提取人脸检测
for (auto it = begin(bboxes); it != end(bboxes); ++it) {
//框选人脸
Rect rec(it->at(0) - padding, it->at(1) - padding, it->at(2) - it->at(0) + 2 * padding,
it->at(3) - it->at(1) + 2 * padding);
//避免人脸框选超过图像边缘
rec.width = ((rec.x + rec.width) > frame.cols) ? (frame.cols - rec.x - 1) : rec.width;
rec.height = ((rec.y + rec.height) > frame.rows) ? (frame.rows - rec.y - 1) : rec.height;
// take the ROI of box on the frame,原图中提取人脸
Mat face = frame(rec);
//性别检测
Mat blob;
blob = blobFromImage(face, 1, Size(227, 227), MODEL_MEAN_VALUES, false);
genderNet.setInput(blob);
// string gender_preds; 获取前向传播softmax结果
vector<float> genderPreds = genderNet.forward();
// find max element index max_element用于找寻最大值
// distance function does the argmax() work in C++ distance返回最大值和第一个值下标的距离
int max_index_gender = std::distance(genderPreds.begin(),
max_element(genderPreds.begin(), genderPreds.end()));
//获得检测结果
string gender = genderList[max_index_gender];
cout << "Gender: " << gender << endl;
//年龄识别
ageNet.setInput(blob);
vector<float> agePreds = ageNet.forward();
// finding maximum indicd in the age_preds vector 找到年龄预测最大下表
int max_indice_age = std::distance(agePreds.begin(), max_element(agePreds.begin(), agePreds.end()));
string age = ageList[max_indice_age];
cout << "Age: " << age << endl;
// label 输出标签
string label = gender + ", " + age;
//在人脸定位图上显示结果
cv::putText(frameFace, label, Point(it->at(0), it->at(1) - 15), cv::FONT_HERSHEY_SIMPLEX, 0.9,
Scalar(0, 255, 255), 2, cv::LINE_AA);
}
//保存结果
imshow("Frame", frameFace);
imwrite("out.jpg", frameFace);
}
}
oushi.jpeg

50.7 KB

oushi1.jpeg

7.75 KB

oushi2.png

41.3 KB

oushi4.png

93.8 KB

oushi5.png

97.7 KB

This source diff could not be displayed because it is too large. You can view the blob instead.
/* stb_image_write - v1.14 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
Before #including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
Will probably not work correctly with strict-aliasing optimizations.
ABOUT:
This header file is a library for writing images to C stdio or a callback.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation; though providing a custom
zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
This library is designed for source code compactness and simplicity,
not optimal image file size or run-time performance.
BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free.
You can #define STBIW_MEMMOVE() to replace memmove()
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
for PNG compression (instead of the builtin one), it must have the following signature:
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
The returned data will be freed with STBIW_FREE() (free() by default),
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
UNICODE:
If compiling for Windows and you wish to use Unicode filenames, compile
with
#define STBIW_WINDOWS_UTF8
and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
Windows wchar_t filenames to utf8.
USAGE:
There are five functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
There are also five equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
where the callback is:
void stbi_write_func(void *context, void *data, int size);
You can configure it with these global variables:
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output.
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP format expands Y to RGB in the file format and does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
PNG allows you to set the deflate compression level by setting the global
variable 'stbi_write_png_compression_level' (it defaults to 8).
HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels.
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
CREDITS:
Sean Barrett - PNG/BMP/TGA
Baldur Karlsson - HDR
Jean-Sebastien Guay - TGA monochrome
Tim Kelsey - misc enhancements
Alan Hickman - TGA RLE
Emmanuel Julien - initial file IO callback implementation
Jon Olick - original jo_jpeg.cpp code
Daniel Gibson - integrate JPEG, allow external zlib
Aarni Koskela - allow choosing PNG filter
bugfixes:
github:Chribba
Guillaume Chereau
github:jry2
github:romigrou
Sergio Gonzalez
Jonas Karlsson
Filip Wasil
Thatcher Ulrich
github:poppolopoppo
Patrick Boettcher
github:xeekworx
Cap Petschulat
Simon Rodriguez
Ivan Tikhonov
github:ignotion
Adam Schackart
LICENSE
See end of file for license information.
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#include <stdlib.h>
// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
#ifndef STBIWDEF
#ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static
#else
#ifdef __cplusplus
#define STBIWDEF extern "C"
#else
#define STBIWDEF extern
#endif
#endif
#endif
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
extern int stbi_write_tga_with_rle;
extern int stbi_write_png_compression_level;
extern int stbi_write_force_png_filter;
#endif
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
#ifdef STBI_WINDOWS_UTF8
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
#endif
typedef void stbi_write_func(void *context, void *data, int size);
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data,
int stride_in_bytes);
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int
stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif
#ifndef STBI_WRITE_NO_STDIO
#include <stdio.h>
#endif // STBI_WRITE_NO_STDIO
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
// ok
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
// ok
#else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
#endif
#ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p, newsz) realloc(p,newsz)
#define STBIW_FREE(p) free(p)
#endif
#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p, oldsz, newsz) STBIW_REALLOC(p,newsz)
#endif
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a, b, sz) memmove(a,b,sz)
#endif
#ifndef STBIW_ASSERT
#include <assert.h>
#define STBIW_ASSERT(x) assert(x)
#endif
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag) {
stbi__flip_vertically_on_write = flag;
}
typedef struct {
stbi_write_func *func;
void *context;
} stbi__write_context;
// initialize a callback-based context
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) {
s->func = c;
s->context = context;
}
#ifndef STBI_WRITE_NO_STDIO
static void stbi__stdio_write(void *context, void *data, int size) {
fwrite(data, 1, size, (FILE *) context);
}
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
#ifdef __cplusplus
#define STBIW_EXTERN extern "C"
#else
#define STBIW_EXTERN extern
#endif
STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
}
#endif
static FILE *stbiw__fopen(char const *filename, char const *mode) {
FILE *f;
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
wchar_t wMode[64];
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
return 0;
#if _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0;
#else
f = _wfopen(wFilename, wMode);
#endif
#elif defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != fopen_s(&f, filename, mode))
f=0;
#else
f = fopen(filename, mode);
#endif
return f;
}
static int stbi__start_write_file(stbi__write_context *s, const char *filename) {
FILE *f = stbiw__fopen(filename, "wb");
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL;
}
static void stbi__end_write_file(stbi__write_context *s) {
fclose((FILE *) s->context);
}
#endif // !STBI_WRITE_NO_STDIO
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1];
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) {
while (*fmt) {
switch (*fmt++) {
case ' ':
break;
case '1': {
unsigned char x = STBIW_UCHAR(va_arg(v, int));
s->func(s->context, &x, 1);
break;
}
case '2': {
int x = va_arg(v, int);
unsigned char b[2];
b[0] = STBIW_UCHAR(x);
b[1] = STBIW_UCHAR(x >> 8);
s->func(s->context, b, 2);
break;
}
case '4': {
stbiw_uint32 x = va_arg(v, int);
unsigned char b[4];
b[0] = STBIW_UCHAR(x);
b[1] = STBIW_UCHAR(x >> 8);
b[2] = STBIW_UCHAR(x >> 16);
b[3] = STBIW_UCHAR(x >> 24);
s->func(s->context, b, 4);
break;
}
default:
STBIW_ASSERT(0);
return;
}
}
}
static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) {
va_list v;
va_start(v, fmt);
stbiw__writefv(s, fmt, v);
va_end(v);
}
static void stbiw__putc(stbi__write_context *s, unsigned char c) {
s->func(s->context, &c, 1);
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) {
unsigned char arr[3];
arr[0] = a;
arr[1] = b;
arr[2] = c;
s->func(s->context, arr, 3);
}
static void
stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) {
unsigned char bg[3] = {255, 0, 255}, px[3];
int k;
if (write_alpha < 0)
s->func(s->context, &d[comp - 1], 1);
switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
case 1:
if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else
s->func(s->context, d, 1); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k = 0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
break;
}
if (write_alpha > 0)
s->func(s->context, &d[comp - 1], 1);
}
static void
stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha,
int scanline_pad, int expand_mono) {
stbiw_uint32 zero = 0;
int i, j, j_end;
if (y <= 0)
return;
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0) {
j_end = -1;
j = y - 1;
} else {
j_end = y;
j = 0;
}
for (; j != j_end; j += vdir) {
for (i = 0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j * x + i) * comp;
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
}
s->func(s->context, &zero, scanline_pad);
}
}
static int
stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data,
int alpha, int pad, const char *fmt, ...) {
if (y < 0 || x < 0) {
return 0;
} else {
va_list v;
va_start(v, fmt);
stbiw__writefv(s, fmt, v);
va_end(v);
stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono);
return 1;
}
}
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) {
int pad = (-x * 3) & 3;
return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *) data, 0, pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, 14 + 40, // file header
40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header
}
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) {
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_bmp_core(&s, x, y, comp, data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) {
stbi__write_context s;
if (stbi__start_write_file(&s, filename)) {
int r = stbi_write_bmp_core(&s, x, y, comp, data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif //!STBI_WRITE_NO_STDIO
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) {
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp - 1 : comp;
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
if (y < 0 || x < 0)
return 0;
if (!stbi_write_tga_with_rle) {
return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8,
has_alpha * 8);
} else {
int i, j, k;
int jend, jdir;
stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8,
has_alpha * 8);
if (stbi__flip_vertically_on_write) {
j = 0;
jend = y;
jdir = 1;
} else {
j = y - 1;
jend = -1;
jdir = -1;
}
for (; j != jend; j += jdir) {
unsigned char *row = (unsigned char *) data + j * x * comp;
int len;
for (i = 0; i < x; i += len) {
unsigned char *begin = row + i * comp;
int diff = 1;
len = 1;
if (i < x - 1) {
++len;
diff = memcmp(begin, row + (i + 1) * comp, comp);
if (diff) {
const unsigned char *prev = begin;
for (k = i + 2; k < x && len < 128; ++k) {
if (memcmp(prev, row + k * comp, comp)) {
prev += comp;
++len;
} else {
--len;
break;
}
}
} else {
for (k = i + 2; k < x && len < 128; ++k) {
if (!memcmp(begin, row + k * comp, comp)) {
++len;
} else {
break;
}
}
}
}
if (diff) {
unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1);
for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
}
} else {
unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
}
}
}
}
return 1;
}
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) {
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_tga_core(&s, x, y, comp, (void *) data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) {
stbi__write_context s;
if (stbi__start_write_file(&s, filename)) {
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) {
int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32f) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f / maxcomp;
rgbe[0] = (unsigned char) (linear[0] * normalize);
rgbe[1] = (unsigned char) (linear[1] * normalize);
rgbe[2] = (unsigned char) (linear[2] * normalize);
rgbe[3] = (unsigned char) (exponent + 128);
}
}
static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) {
unsigned char lengthbyte = STBIW_UCHAR(length + 128);
STBIW_ASSERT(length + 128 <= 255);
s->func(s->context, &lengthbyte, 1);
s->func(s->context, &databyte, 1);
}
static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) {
unsigned char lengthbyte = STBIW_UCHAR(length);
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
s->func(s->context, &lengthbyte, 1);
s->func(s->context, data, length);
}
static void
stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) {
unsigned char scanlineheader[4] = {2, 2, 0, 0};
unsigned char rgbe[4];
float linear[3];
int x;
scanlineheader[2] = (width & 0xff00) >> 8;
scanlineheader[3] = (width & 0x00ff);
/* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x = 0; x < width; x++) {
switch (ncomp) {
case 4: /* fallthrough */
case 3:
linear[2] = scanline[x * ncomp + 2];
linear[1] = scanline[x * ncomp + 1];
linear[0] = scanline[x * ncomp + 0];
break;
default:
linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
s->func(s->context, rgbe, 4);
}
} else {
int c, r;
/* encode into scratch buffer */
for (x = 0; x < width; x++) {
switch (ncomp) {
case 4: /* fallthrough */
case 3:
linear[2] = scanline[x * ncomp + 2];
linear[1] = scanline[x * ncomp + 1];
linear[0] = scanline[x * ncomp + 0];
break;
default:
linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
scratch[x + width * 0] = rgbe[0];
scratch[x + width * 1] = rgbe[1];
scratch[x + width * 2] = rgbe[2];
scratch[x + width * 3] = rgbe[3];
}
s->func(s->context, scanlineheader, 4);
/* RLE each component separately */
for (c = 0; c < 4; c++) {
unsigned char *comp = &scratch[width * c];
x = 0;
while (x < width) {
// find first run
r = x;
while (r + 2 < width) {
if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2])
break;
++r;
}
if (r + 2 >= width)
r = width;
// dump up to first run
while (x < r) {
int len = r - x;
if (len > 128) len = 128;
stbiw__write_dump_data(s, len, &comp[x]);
x += len;
}
// if there's a run, output it
if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd
// find next byte after run
while (r < width && comp[r] == comp[x])
++r;
// output run up to r
while (x < r) {
int len = r - x;
if (len > 127) len = 127;
stbiw__write_run_data(s, len, comp[x]);
x += len;
}
}
}
}
}
}
static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) {
if (y <= 0 || x <= 0 || data == NULL)
return 0;
else {
// Each component is stored separately. Allocate scratch space for full output scanline.
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x * 4);
int i, len;
char buffer[128];
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header) - 1);
#ifdef __STDC_WANT_SECURE_LIB__
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len);
for (i = 0; i < y; i++)
stbiw__write_hdr_scanline(s, x, comp, scratch,
data + comp * x * (stbi__flip_vertically_on_write ? y - 1 - i : i));
STBIW_FREE(scratch);
return 1;
}
}
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) {
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) {
stbi__write_context s;
if (stbi__start_write_file(&s, filename)) {
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif // STBI_WRITE_NO_STDIO
//////////////////////////////////////////////////////////////////////////////
//
// PNG writer
//
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
#define stbiw__sbneedgrow(a, n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
#define stbiw__sbmaybegrow(a, n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
#define stbiw__sbgrow(a, n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) {
int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1;
void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0,
*arr ? (stbiw__sbm(*arr) * itemsize + sizeof(int) * 2) : 0,
itemsize * m + sizeof(int) * 2);
STBIW_ASSERT(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbiw__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) {
while (*bitcount >= 8) {
stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbiw__zlib_bitrev(int code, int codebits) {
int res = 0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) {
int i;
for (i = 0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbiw__zhash(unsigned char *data) {
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
#define stbiw__zlib_add(code, codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b, c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
// default huffman tables
#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
#define stbiw__ZHASH 16384
#endif // STBIW_ZLIB_COMPRESS
STBIWDEF unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) {
#ifdef STBIW_ZLIB_COMPRESS
// user provided a zlib compress implementation, use that
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
#else // use builtin
static unsigned short lengthc[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83,
99, 115, 131, 163, 195, 227, 258, 259};
static unsigned char lengtheb[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
5, 0};
static unsigned short distc[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769,
1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32768};
static unsigned char disteb[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
unsigned int bitbuf = 0;
int i, j, bitcount = 0;
unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char ***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char **));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
stbiw__sbpush(out, 0x5e); // FLEVEL = 1
stbiw__zlib_add(1, 1); // BFINAL = 1
stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman
for (i = 0; i < stbiw__ZHASH; ++i)
hash_table[i] = NULL;
i = 0;
while (i < data_len - 3) {
// hash next 3 bytes of data to be compressed
int h = stbiw__zhash(data + i) & (stbiw__ZHASH - 1), best = 3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbiw__sbcount(hlist);
for (j = 0; j < n; ++j) {
if (hlist[j] - data > i - 32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i);
if (d >= best) {
best = d;
bestloc = hlist[j];
}
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) {
STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0]) * quality);
stbiw__sbn(hash_table[h]) = quality;
}
stbiw__sbpush(hash_table[h], data + i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbiw__zhash(data + i + 1) & (stbiw__ZHASH - 1);
hlist = hash_table[h];
n = stbiw__sbcount(hlist);
for (j = 0; j < n; ++j) {
if (hlist[j] - data > i - 32767) {
int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = (int) (data + i - bestloc); // distance back
STBIW_ASSERT(d <= 32767 && best <= 258);
for (j = 0; best > lengthc[j + 1] - 1; ++j);
stbiw__zlib_huff(j + 257);
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
for (j = 0; d > distc[j + 1] - 1; ++j);
stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5);
if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbiw__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (; i < data_len; ++i)
stbiw__zlib_huffb(data[i]);
stbiw__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbiw__zlib_add(0, 1);
for (i = 0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
{
// compute adler32 on input
unsigned int s1 = 1, s2 = 0;
int blocklen = (int) (data_len % 5552);
j = 0;
while (j < data_len) {
for (i = 0; i < blocklen; ++i) {
s1 += data[j + i];
s2 += s1;
}
s1 %= 65521;
s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
stbiw__sbpush(out, STBIW_UCHAR(s2));
stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
stbiw__sbpush(out, STBIW_UCHAR(s1));
}
*out_len = stbiw__sbn(out);
// make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out);
#endif // STBIW_ZLIB_COMPRESS
}
static unsigned int stbiw__crc32(unsigned char *buffer, int len) {
#ifdef STBIW_CRC32
return STBIW_CRC32(buffer, len);
#else
static unsigned int crc_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
unsigned int crc = ~0u;
int i;
for (i = 0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
#endif
}
#define stbiw__wpng4(o, a, b, c, d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
#define stbiw__wp32(data, v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data, s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
static void stbiw__wpcrc(unsigned char **data, int len) {
unsigned int crc = stbiw__crc32(*data - len - 4, len + 4);
stbiw__wp32(*data, crc);
}
static unsigned char stbiw__paeth(int a, int b, int c) {
int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
if (pb <= pc) return STBIW_UCHAR(b);
return STBIW_UCHAR(c);
}
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
static void
stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type,
signed char *line_buffer) {
static int mapping[] = {0, 1, 2, 3, 4};
static int firstmap[] = {0, 1, 0, 5, 6};
int *mymap = (y != 0) ? mapping : firstmap;
int i;
int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y);
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
if (type == 0) {
memcpy(line_buffer, z, width * n);
return;
}
// first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) {
switch (type) {
case 1:
line_buffer[i] = z[i];
break;
case 2:
line_buffer[i] = z[i] - z[i - signed_stride];
break;
case 3:
line_buffer[i] = z[i] - (z[i - signed_stride] >> 1);
break;
case 4:
line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0, z[i - signed_stride], 0));
break;
case 5:
line_buffer[i] = z[i];
break;
case 6:
line_buffer[i] = z[i];
break;
}
}
switch (type) {
case 1:
for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - z[i - n];
break;
case 2:
for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - z[i - signed_stride];
break;
case 3:
for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1);
break;
case 4:
for (i = n; i < width * n; ++i)
line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], z[i - signed_stride - n]);
break;
case 5:
for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - (z[i - n] >> 1);
break;
case 6:
for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0);
break;
}
}
STBIWDEF unsigned char *
stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) {
int force_filter = stbi_write_force_png_filter;
int ctype[5] = {-1, 0, 4, 2, 6};
unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
unsigned char *out, *o, *filt, *zlib;
signed char *line_buffer;
int j, zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
if (force_filter >= 5) {
force_filter = -1;
}
filt = (unsigned char *) STBIW_MALLOC((x * n + 1) * y);
if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n);
if (!line_buffer) {
STBIW_FREE(filt);
return 0;
}
for (j = 0; j < y; ++j) {
int filter_type;
if (force_filter > -1) {
filter_type = force_filter;
stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);
} else { // Estimate the best filter by running through all of them:
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
for (filter_type = 0; filter_type < 5; filter_type++) {
stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);
// Estimate the entropy of the line using this filter; the less, the better.
est = 0;
for (i = 0; i < x * n; ++i) {
est += abs((signed char) line_buffer[i]);
}
if (est < best_filter_val) {
best_filter_val = est;
best_filter = filter_type;
}
}
if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);
filter_type = best_filter;
}
}
// when we get here, filter_type contains the filter type, and line_buffer contains the data
filt[j * (x * n + 1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt + j * (x * n + 1) + 1, line_buffer, x * n);
}
STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, stbi_write_png_compression_level);
STBIW_FREE(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12);
if (!out) return 0;
*out_len = 8 + 12 + 13 + 12 + zlen + 12;
o = out;
STBIW_MEMMOVE(o, sig, 8);
o += 8;
stbiw__wp32(o, 13); // header length
stbiw__wptag(o, "IHDR");
stbiw__wp32(o, x);
stbiw__wp32(o, y);
*o++ = 8;
*o++ = STBIW_UCHAR(ctype[n]);
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbiw__wpcrc(&o, 13);
stbiw__wp32(o, zlen);
stbiw__wptag(o, "IDAT");
STBIW_MEMMOVE(o, zlib, zlen);
o += zlen;
STBIW_FREE(zlib);
stbiw__wpcrc(&o, zlen);
stbiw__wp32(o, 0);
stbiw__wptag(o, "IEND");
stbiw__wpcrc(&o, 0);
STBIW_ASSERT(o == out + *out_len);
return out;
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) {
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0;
f = stbiw__fopen(filename, "wb");
if (!f) {
STBIW_FREE(png);
return 0;
}
fwrite(png, 1, len, f);
fclose(f);
STBIW_FREE(png);
return 1;
}
#endif
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data,
int stride_bytes) {
int len;
unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0;
func(context, png, len);
STBIW_FREE(png);
return 1;
}
/* ***************************************************************************
*
* JPEG writer
*
* This is based on Jon Olick's jo_jpeg.cpp:
* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
*/
static const unsigned char stbiw__jpg_ZigZag[] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17,
25, 30, 41, 43, 9, 11, 18,
24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38,
46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57,
58, 62, 63};
static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
int bitBuf = *bitBufP, bitCnt = *bitCntP;
bitCnt += bs[1];
bitBuf |= bs[0] << (24 - bitCnt);
while (bitCnt >= 8) {
unsigned char c = (bitBuf >> 16) & 255;
stbiw__putc(s, c);
if (c == 255) {
stbiw__putc(s, 0);
}
bitBuf <<= 8;
bitCnt -= 8;
}
*bitBufP = bitBuf;
*bitCntP = bitCnt;
}
static void
stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
float z1, z2, z3, z4, z5, z11, z13;
float tmp0 = d0 + d7;
float tmp7 = d0 - d7;
float tmp1 = d1 + d6;
float tmp6 = d1 - d6;
float tmp2 = d2 + d5;
float tmp5 = d2 - d5;
float tmp3 = d3 + d4;
float tmp4 = d3 - d4;
// Even part
float tmp10 = tmp0 + tmp3; // phase 2
float tmp13 = tmp0 - tmp3;
float tmp11 = tmp1 + tmp2;
float tmp12 = tmp1 - tmp2;
d0 = tmp10 + tmp11; // phase 3
d4 = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * 0.707106781f; // c4
d2 = tmp13 + z1; // phase 5
d6 = tmp13 - z1;
// Odd part
tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations.
z5 = (tmp10 - tmp12) * 0.382683433f; // c6
z2 = tmp10 * 0.541196100f + z5; // c2-c6
z4 = tmp12 * 1.306562965f + z5; // c2+c6
z3 = tmp11 * 0.707106781f; // c4
z11 = tmp7 + z3; // phase 5
z13 = tmp7 - z3;
*d5p = z13 + z2; // phase 6
*d3p = z13 - z2;
*d1p = z11 + z4;
*d7p = z11 - z4;
*d0p = d0;
*d2p = d2;
*d4p = d4;
*d6p = d6;
}
static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
int tmp1 = val < 0 ? -val : val;
val = val < 0 ? val - 1 : val;
bits[1] = 1;
while (tmp1 >>= 1) {
++bits[1];
}
bits[0] = val & ((1 << bits[1]) - 1);
}
static int
stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC,
const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = {HTAC[0x00][0], HTAC[0x00][1]};
const unsigned short M16zeroes[2] = {HTAC[0xF0][0], HTAC[0xF0][1]};
int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64];
// DCT rows
for (dataOff = 0, n = du_stride * 8; dataOff < n; dataOff += du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 1], &CDU[dataOff + 2], &CDU[dataOff + 3], &CDU[dataOff + 4],
&CDU[dataOff + 5], &CDU[dataOff + 6], &CDU[dataOff + 7]);
}
// DCT columns
for (dataOff = 0; dataOff < 8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + du_stride], &CDU[dataOff + du_stride * 2],
&CDU[dataOff + du_stride * 3], &CDU[dataOff + du_stride * 4],
&CDU[dataOff + du_stride * 5], &CDU[dataOff + du_stride * 6], &CDU[dataOff + du_stride * 7]);
}
// Quantize/descale/zigzag the coefficients
for (y = 0, j = 0; y < 8; ++y) {
for (x = 0; x < 8; ++x, ++j) {
float v;
i = y * du_stride + x;
v = CDU[i] * fdtbl[j];
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[j]] = (int) (v < 0 ? v - 0.5f : v + 0.5f);
}
}
// Encode DC
diff = DU[0] - DC;
if (diff == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
} else {
unsigned short bits[2];
stbiw__jpg_calcBits(diff, bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
// Encode ACs
end0pos = 63;
for (; (end0pos > 0) && (DU[end0pos] == 0); --end0pos) {
}
// end0pos = first element in reverse order !=0
if (end0pos == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
return DU[0];
}
for (i = 1; i <= end0pos; ++i) {
int startpos = i;
int nrzeroes;
unsigned short bits[2];
for (; DU[i] == 0 && i <= end0pos; ++i) {
}
nrzeroes = i - startpos;
if (nrzeroes >= 16) {
int lng = nrzeroes >> 4;
int nrmarker;
for (nrmarker = 1; nrmarker <= lng; ++nrmarker)
stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
nrzeroes &= 15;
}
stbiw__jpg_calcBits(DU[i], bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
if (end0pos != 63) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
}
return DU[0];
}
static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void *data, int quality) {
// Constants that don't pollute global namespace
static const unsigned char std_dc_luminance_nrcodes[] = {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
static const unsigned char std_dc_luminance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static const unsigned char std_ac_luminance_nrcodes[] = {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
static const unsigned char std_ac_luminance_values[] = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
};
static const unsigned char std_dc_chrominance_nrcodes[] = {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const unsigned char std_dc_chrominance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static const unsigned char std_ac_chrominance_nrcodes[] = {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};
static const unsigned char std_ac_chrominance_values[] = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
};
// Huffman tables
static const unsigned short YDC_HT[256][2] = {{0, 2},
{2, 3},
{3, 3},
{4, 3},
{5, 3},
{6, 3},
{14, 4},
{30, 5},
{62, 6},
{126, 7},
{254, 8},
{510, 9}};
static const unsigned short UVDC_HT[256][2] = {{0, 2},
{1, 2},
{2, 2},
{6, 3},
{14, 4},
{30, 5},
{62, 6},
{126, 7},
{254, 8},
{510, 9},
{1022, 10},
{2046, 11}};
static const unsigned short YAC_HT[256][2] = {
{10, 4},
{0, 2},
{1, 2},
{4, 3},
{11, 4},
{26, 5},
{120, 7},
{248, 8},
{1014, 10},
{65410, 16},
{65411, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{12, 4},
{27, 5},
{121, 7},
{502, 9},
{2038, 11},
{65412, 16},
{65413, 16},
{65414, 16},
{65415, 16},
{65416, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{28, 5},
{249, 8},
{1015, 10},
{4084, 12},
{65417, 16},
{65418, 16},
{65419, 16},
{65420, 16},
{65421, 16},
{65422, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{58, 6},
{503, 9},
{4085, 12},
{65423, 16},
{65424, 16},
{65425, 16},
{65426, 16},
{65427, 16},
{65428, 16},
{65429, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{59, 6},
{1016, 10},
{65430, 16},
{65431, 16},
{65432, 16},
{65433, 16},
{65434, 16},
{65435, 16},
{65436, 16},
{65437, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{122, 7},
{2039, 11},
{65438, 16},
{65439, 16},
{65440, 16},
{65441, 16},
{65442, 16},
{65443, 16},
{65444, 16},
{65445, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{123, 7},
{4086, 12},
{65446, 16},
{65447, 16},
{65448, 16},
{65449, 16},
{65450, 16},
{65451, 16},
{65452, 16},
{65453, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{250, 8},
{4087, 12},
{65454, 16},
{65455, 16},
{65456, 16},
{65457, 16},
{65458, 16},
{65459, 16},
{65460, 16},
{65461, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{504, 9},
{32704, 15},
{65462, 16},
{65463, 16},
{65464, 16},
{65465, 16},
{65466, 16},
{65467, 16},
{65468, 16},
{65469, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{505, 9},
{65470, 16},
{65471, 16},
{65472, 16},
{65473, 16},
{65474, 16},
{65475, 16},
{65476, 16},
{65477, 16},
{65478, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{506, 9},
{65479, 16},
{65480, 16},
{65481, 16},
{65482, 16},
{65483, 16},
{65484, 16},
{65485, 16},
{65486, 16},
{65487, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1017, 10},
{65488, 16},
{65489, 16},
{65490, 16},
{65491, 16},
{65492, 16},
{65493, 16},
{65494, 16},
{65495, 16},
{65496, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1018, 10},
{65497, 16},
{65498, 16},
{65499, 16},
{65500, 16},
{65501, 16},
{65502, 16},
{65503, 16},
{65504, 16},
{65505, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2040, 11},
{65506, 16},
{65507, 16},
{65508, 16},
{65509, 16},
{65510, 16},
{65511, 16},
{65512, 16},
{65513, 16},
{65514, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{65515, 16},
{65516, 16},
{65517, 16},
{65518, 16},
{65519, 16},
{65520, 16},
{65521, 16},
{65522, 16},
{65523, 16},
{65524, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2041, 11},
{65525, 16},
{65526, 16},
{65527, 16},
{65528, 16},
{65529, 16},
{65530, 16},
{65531, 16},
{65532, 16},
{65533, 16},
{65534, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}
};
static const unsigned short UVAC_HT[256][2] = {
{0, 2},
{1, 2},
{4, 3},
{10, 4},
{24, 5},
{25, 5},
{56, 6},
{120, 7},
{500, 9},
{1014, 10},
{4084, 12},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{11, 4},
{57, 6},
{246, 8},
{501, 9},
{2038, 11},
{4085, 12},
{65416, 16},
{65417, 16},
{65418, 16},
{65419, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{26, 5},
{247, 8},
{1015, 10},
{4086, 12},
{32706, 15},
{65420, 16},
{65421, 16},
{65422, 16},
{65423, 16},
{65424, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{27, 5},
{248, 8},
{1016, 10},
{4087, 12},
{65425, 16},
{65426, 16},
{65427, 16},
{65428, 16},
{65429, 16},
{65430, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{58, 6},
{502, 9},
{65431, 16},
{65432, 16},
{65433, 16},
{65434, 16},
{65435, 16},
{65436, 16},
{65437, 16},
{65438, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{59, 6},
{1017, 10},
{65439, 16},
{65440, 16},
{65441, 16},
{65442, 16},
{65443, 16},
{65444, 16},
{65445, 16},
{65446, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{121, 7},
{2039, 11},
{65447, 16},
{65448, 16},
{65449, 16},
{65450, 16},
{65451, 16},
{65452, 16},
{65453, 16},
{65454, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{122, 7},
{2040, 11},
{65455, 16},
{65456, 16},
{65457, 16},
{65458, 16},
{65459, 16},
{65460, 16},
{65461, 16},
{65462, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{249, 8},
{65463, 16},
{65464, 16},
{65465, 16},
{65466, 16},
{65467, 16},
{65468, 16},
{65469, 16},
{65470, 16},
{65471, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{503, 9},
{65472, 16},
{65473, 16},
{65474, 16},
{65475, 16},
{65476, 16},
{65477, 16},
{65478, 16},
{65479, 16},
{65480, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{504, 9},
{65481, 16},
{65482, 16},
{65483, 16},
{65484, 16},
{65485, 16},
{65486, 16},
{65487, 16},
{65488, 16},
{65489, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{505, 9},
{65490, 16},
{65491, 16},
{65492, 16},
{65493, 16},
{65494, 16},
{65495, 16},
{65496, 16},
{65497, 16},
{65498, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{506, 9},
{65499, 16},
{65500, 16},
{65501, 16},
{65502, 16},
{65503, 16},
{65504, 16},
{65505, 16},
{65506, 16},
{65507, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{2041, 11},
{65508, 16},
{65509, 16},
{65510, 16},
{65511, 16},
{65512, 16},
{65513, 16},
{65514, 16},
{65515, 16},
{65516, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{16352, 14},
{65517, 16},
{65518, 16},
{65519, 16},
{65520, 16},
{65521, 16},
{65522, 16},
{65523, 16},
{65524, 16},
{65525, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{1018, 10},
{32707, 15},
{65526, 16},
{65527, 16},
{65528, 16},
{65529, 16},
{65530, 16},
{65531, 16},
{65532, 16},
{65533, 16},
{65534, 16},
{0, 0},
{0, 0},
{0, 0},
{0, 0},
{0, 0}
};
static const int YQT[] = {16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57,
69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22,
37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120,
101, 72, 92, 95, 98, 112, 100, 103, 99};
static const int UVQT[] = {17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99,
99, 99, 47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99};
static const float aasf[] = {1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f,
1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f,
0.275899379f * 2.828427125f};
int row, col, i, k, subsample;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
if (!data || !width || !height || comp > 4 || comp < 1) {
return 0;
}
quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
for (i = 0; i < 64; ++i) {
int uvti, yti = (YQT[i] * quality + 50) / 100;
YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
uvti = (UVQT[i] * quality + 50) / 100;
UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
}
for (row = 0, k = 0; row < 8; ++row) {
for (col = 0; col < 8; ++col, ++k) {
fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
}
}
// Write Headers
{
static const unsigned char head0[] = {0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 'J', 'F', 'I', 'F', 0, 1, 1, 0, 0, 1, 0,
1, 0, 0, 0xFF, 0xDB, 0, 0x84, 0};
static const unsigned char head2[] = {0xFF, 0xDA, 0, 0xC, 3, 1, 0, 2, 0x11, 3, 0x11, 0, 0x3F, 0};
const unsigned char head1[] = {0xFF, 0xC0, 0, 0x11, 8, (unsigned char) (height >> 8), STBIW_UCHAR(height),
(unsigned char) (width >> 8), STBIW_UCHAR(width),
3, 1, (unsigned char) (subsample ? 0x22 : 0x11), 0, 2, 0x11, 1, 3, 0x11, 1, 0xFF,
0xC4, 0x01, 0xA2, 0};
s->func(s->context, (void *) head0, sizeof(head0));
s->func(s->context, (void *) YTable, sizeof(YTable));
stbiw__putc(s, 1);
s->func(s->context, UVTable, sizeof(UVTable));
s->func(s->context, (void *) head1, sizeof(head1));
s->func(s->context, (void *) (std_dc_luminance_nrcodes + 1), sizeof(std_dc_luminance_nrcodes) - 1);
s->func(s->context, (void *) std_dc_luminance_values, sizeof(std_dc_luminance_values));
stbiw__putc(s, 0x10); // HTYACinfo
s->func(s->context, (void *) (std_ac_luminance_nrcodes + 1), sizeof(std_ac_luminance_nrcodes) - 1);
s->func(s->context, (void *) std_ac_luminance_values, sizeof(std_ac_luminance_values));
stbiw__putc(s, 1); // HTUDCinfo
s->func(s->context, (void *) (std_dc_chrominance_nrcodes + 1), sizeof(std_dc_chrominance_nrcodes) - 1);
s->func(s->context, (void *) std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
stbiw__putc(s, 0x11); // HTUACinfo
s->func(s->context, (void *) (std_ac_chrominance_nrcodes + 1), sizeof(std_ac_chrominance_nrcodes) - 1);
s->func(s->context, (void *) std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
s->func(s->context, (void *) head2, sizeof(head2));
}
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
int DCY = 0, DCU = 0, DCV = 0;
int bitBuf = 0, bitCnt = 0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *) data;
const unsigned char *dataG = dataR + ofsG;
const unsigned char *dataB = dataR + ofsB;
int x, y, pos;
if (subsample) {
for (y = 0; y < height; y += 16) {
for (x = 0; x < width; x += 16) {
float Y[256], U[256], V[256];
for (row = y, pos = 0; row < y + 16; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p =
(stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width *
comp;
for (col = x; col < x + 16; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width - 1)) * comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128;
U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b;
V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
// subsample U,V
{
float subU[64], subV[64];
int yy, xx;
for (yy = 0, pos = 0; yy < 8; ++yy) {
for (xx = 0; xx < 8; ++xx, ++pos) {
int j = yy * 32 + xx * 2;
subU[pos] = (U[j + 0] + U[j + 1] + U[j + 16] + U[j + 17]) * 0.25f;
subV[pos] = (V[j + 0] + V[j + 1] + V[j + 16] + V[j + 17]) * 0.25f;
}
}
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
} else {
for (y = 0; y < height; y += 8) {
for (x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for (row = y, pos = 0; row < y + 8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p =
(stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width *
comp;
for (col = x; col < x + 8; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width - 1)) * comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128;
U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b;
V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
// Do the bit alignment of the EOI marker
stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
}
// EOI
stbiw__putc(s, 0xFF);
stbiw__putc(s, 0xD9);
return 1;
}
STBIWDEF int
stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) {
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) {
stbi__write_context s;
if (stbi__start_write_file(&s, filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1.13
1.12
1.11 (2019-08-11)
1.10 (2019-02-07)
support utf8 filenames in Windows; fix warnings and platform ifdefs
1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29)
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
1.07 (2017-07-24)
doc fix
1.06 (2017-07-23)
writing JPEG (using Jon Olick's code)
1.05 ???
1.04 (2017-03-03)
monochrome BMP expansion
1.03 ???
1.02 (2016-04-02)
avoid allocating large structures on the stack
1.01 (2016-01-16)
STBIW_REALLOC_SIZED: support allocators with no realloc support
avoid race-condition in crc initialization
minor compile issues
1.00 (2015-09-14)
installable file IO function
0.99 (2015-09-13)
warning fixes; TGA rle support
0.98 (2015-04-08)
added STBIW_MALLOC, STBIW_ASSERT etc
0.97 (2015-01-18)
fixed HDR asserts, rewrote HDR rle logic
0.96 (2015-01-17)
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
warning fixes
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment